关于lua:如何将一个-Lua-Table-序列化

 有时因为业务须要,要将一个 Lua Table 序列化,如果不在乎序列化后果的可读性,能够间接将 Table 序列化成二进制数据块,如果须要后果的可读性,能够将 Table 序列化成字符串。 要序列化的内容 因为 Lua 的 Table 中能够保留各种各样的内容,不可能都序列化,而且根本也不会有这种需要,比方像是 Function 这种变量,序列化进去并无意义,因为在另一个环境下反序列化当前就不能用了。 出于这个起因, Function 和 Thread 变量不论是 key 还是 value 都不会解决。如果 key 是 Table 变量,则也不解决,同时 Table 中不能有对其它 Table 的循环援用。 尽管看起来有一些限度,然而因为序列化 Table 个别都是用在保留或者发送上,所以其实自身就基本上不会有这种受限制的需要。 二进制 将 Table 序列化为二进制数据块的速度是最快的,体积也是最小的,如果没有可读性要求,且序列化远比反序列化的次数多,那就果决抉择序列化成二进制。 云风大佬有一个现成的实现能够间接拿来用 lua-serialize,本人实现一个也不难,就是应用 Lua 提供的 C Api 遍历 Table,而后依据 key 和 value 的类型,一直写入到一个能够动静扩容的内存块链表中,全副写入实现当前再将链表中的所有块拷贝进一个间断内存中。 除了后果没有可读性以外,序列化成二进制还有一个毛病就是后果要反序列化成 Table 的时候仍然须要逆向解析一遍。 字符串 序列化成字符串的长处是,后果可读性好,而且不须要额定实现反序列化,能够间接应用 load 来加载字符串实现反序列化。 Lua 实现 用 Lua 来实现是最顺畅最简略的,不必写 C 代码,也不须要编译。如果没有高频应用的话,用 Lua 序列化就足够用了。 有一个十分好的第三方实现能够用来解决这个问题,serpent,功能强大,不仅能够序列化,还能够将 Table 以可读形式打印进去。 ...

August 30, 2023 · 1 min · jiezi

关于lua:构建Lua解释器虚拟机的基础

前言在本篇,咱们正式进入到Lua解释器的开发阶段(这是一个遵循Lua 5.3规范的我的项目)。本篇并不间接接入到设计和实现语法分析器和词法分析器的阶段,而是先设计和实现Lua虚拟机的根底数据结构(包含Lua最根本的数据结构,如根本数据类型、示意虚拟机状态的global_State和lua_State构造、在函数调用中表演重要角色的CallInfo构造等)以及设计和实现基于栈的C函数调用流程。这些都是了解前面虚拟机运作的根底。因为这是一个仿造我的项目,为了和官网版本做辨别,就称之为dummylua,前面要称说本我的项目时,一律用dummylua来示意。 本篇将分为几个局部:首先介绍工程目录构造的组织,以及为什么要这样组织,每个目录别离蕴含哪些文件,这些文件别离蕴含哪些内容;其次是着手进行Lua根本类型的设计与实现,实现示意Lua虚拟机状态的global_State和lua_State构造,以及用于函数调用的CallInfo构造;接着是设计咱们在应用层,要实现C函数,在栈中调用流程的API,并且构建从虚拟机状态初始化到函数实现调用的逻辑图,论述这个过程;最初通过编写代码,将所有的流程实现。第一局部的性能曾经实现开发和测试(Ubuntu、Mac和Windows平台)。 获取源码能够查看:https://github.com/Manistein/... 目录构造在开始介绍我的项目的目录构造之前,咱们无妨先回顾一下Lua运作的两种基本模式。 一种是创立Lua虚拟机,间接加载脚本并且间接运行,其遵循如下流程: 创立Lua虚拟机状态实例加载规范库加载脚本,通过词法分析器Lexer和语法分析器Parser将脚本编译成Lua虚拟机可能辨认的Opcodes,并存储在虚拟机状态实例中运行虚拟机,对虚拟机状态实例中的Opcodes进行执行还有一种则是,事后将脚本编译,而后将内存中的指令信息,Dump到文件中,以Bytecode的模式存在,当前要运行的时候,间接加载Dump文件的Bytecode并且间接运行: 创立Lua虚拟机状态实例加载规范库加载脚本,通过词法分析器Lexer和语法分析器Parser将脚本编译成Lua虚拟机可能辨认的Opcodes,并存储在虚拟机状态实例中将虚拟机指令Dump成二进制文件,以Bytecode的模式保留在未来某个时刻,运行Lua虚拟机,并加载Dump后的文件,间接通过Dump数据,将指令构造还原回来,保留在虚拟机状态实例中运行虚拟机,对虚拟机状态实例中的Opcodes进行执行这两种形式,前者从虚拟机创立到加载脚本,再到运行零打碎敲。后者须要事后将Lua脚本编译成Bytecode,而后要应用的时候再加载运行,运行时省去了编译流程,比前者更快。不过当初Lua间接加载脚本并运行曾经足够快了,除非对性能有极其刻薄的要求,否则前者曾经可能满足咱们的日常须要了。上面援用一张《The Lua Architecture》(Reference 1)中的一张图,来展现一下前面一种形式的流程。 从上图,咱们能够理解到一个流程,就是咱们要运行Lua脚本,首先要创立Lua解释器(因为Lua是采纳纯C来写的工程,因而函数和数据是拆散的,这里其实也只是创立一个Lua虚拟机状态实例,也就是前面咱们要介绍的lua_State构造和global_State构造),而后通过编译器(Lexer和Parser)将脚本编译成虚拟机可能辨认的指令(Opcodes),再交给虚拟机执行。因而,咱们能够将编译和运行宰割开来,他们独特应用的局部也独自抽离进去,于是咱们的目录构造能够按如下所示的形式组织: + 3rd/ #援用的第三方库均搁置在这里+ bin/ #编译生成的二进制文件搁置在这里+ clib/ #内部要在c层应用Lua的C API,那么只能调用clib里提供的接口,而不能调用其余外部接口+ common/ #vm和compiler独特应用的构造、接口均搁置在这里+ compiler/ #编译器相干的局部搁置在这里+ test/ #测试用例全副搁置在这里+ vm/ #虚拟机相干的局部搁置在这里 main.c makefile咱们有理由置信,目录组织也是架构的一部分,下面附上了目录阐明,可能清晰阐明他们的分类和作用。我想构建的逻辑档次图如下所示: 3rd和common作为vm和compiler的根底模块而存在,内部在应用c接口的时候,只能通过clib里的辅助库来进行,以暗藏不必要裸露的细节。在定下目录构造当前,接下来将展现不同的文件别离有哪些文件。 目录组织实现当前,接下来确定有哪些文件了,我将文件内容展现到上面局部: + 3rd/ #援用的第三方库均搁置在这里+ bin/ #编译生成的二进制文件搁置在这里~ clib/ #内部要在c层应用Lua的C API,那么只能调用clib里提供的接口,而不能调用其余外部接口 luaaux.h #供内部应用的辅助库 luaaux.c~ common/ #vm和compiler独特应用的构造、接口均搁置在这里 lua.h #提供lua根本类型的定义,错误码定义,全我的项目都可能用到的宏均会搁置在这里 luamem.h #lua内存分配器 luamem.c luaobject.h #lua根本类型 luaobject.c luastate.h #虚拟机状态构造,以及对其相干操作的接口均搁置于此 luastate.c+ compiler/ #编译器相干的局部搁置在这里+ test/ #测试用例全副搁置在这里~ vm/ #虚拟机相干的局部搁置在这里 luado.h #函数调用相干的接口均搁置于此 luado.c main.c makefile下面展现了咱们本局部要实现的局部,后续开发会陆续增加新的文件,前面章节也会陆续援用这个片段。到当初为止,咱们的目录构造就介绍完了,前面将介绍根本数据结构。 根本数据结构根本类型Lua的根本类型,包含lua_Integer、lua_Number、lu_byte、lua_CFunction等,当然最典型的则是其可能代表任何根本类型的TValue构造。当初咱们将逐个实现这些类型。 首先咱们要实现两个宏,LUA_INTEGER和LUA_NUMBER在common/lua.h里: ...

February 9, 2023 · 11 min · jiezi

关于lua:Y-分钟速成-Lua

源代码下载: lua-cn.lua -- 单行正文以两个连字符结尾 --[[ 多行正文--]]---------------------------------------------------- -- 1. 变量和流程管制---------------------------------------------------- num = 42 -- 所有的数字都是双精度浮点型。-- 别胆怯,64位的双精度浮点型数字中有52位用于 -- 保留准确的整型值; 对于52位以内的整型值, -- 不必放心精度问题。s = 'walternate' -- 和Python一样,字符串不可变。 t = "也能够用双引号" u = [[ 多行的字符串 以两个方括号 开始和结尾。]] t = nil -- 撤销t的定义; Lua 反对垃圾回收。 -- 块应用do/end之类的关键字标识: while num < 50 do num = num + 1 -- 不反对 ++ 或 += 运算符。 end -- If语句: if num > 40 then print('over 40') elseif s ~= 'walternate' then -- ~= 示意不等于。 -- 像Python一样,用 == 查看是否相等 ;字符串同样实用。 io.write('not over 40\n') -- 默认规范输入。else -- 默认全局变量。 thisIsGlobal = 5 -- 通常应用驼峰。 -- 如何定义局部变量: local line = io.read() -- 读取规范输出的下一行。 -- ..操作符用于连贯字符串: print('Winter is coming, ' .. line) end -- 未定义的变量返回nil。 -- 这不是谬误: foo = anUnknownVariable -- 当初 foo = nil. aBoolValue = false --只有nil和false为假; 0和 ''均为真! if not aBoolValue then print('false') end -- 'or'和 'and'短路 -- 相似于C/js里的 a?b:c 操作符: ans = aBoolValue and 'yes' or 'no' --> 'no' karlSum = 0 for i = 1, 100 do -- 范畴蕴含两端 karlSum = karlSum + i end -- 应用 "100, 1, -1" 示意递加的范畴: fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- 通常,范畴表达式为begin, end[, step]. -- 循环的另一种构造: repeat print('the way of the future') num = num - 1 until num == 0 ---------------------------------------------------- -- 2. 函数。 ---------------------------------------------------- function fib(n) if n < 2 then return n end return fib(n - 2) + fib(n - 1)end-- 反对闭包及匿名函数: function adder(x) -- 调用adder时,会创立返回的函数, -- 并且会记住x的值: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- 返回值、函数调用和赋值都能够-- 应用长度不匹配的list。 -- 不匹配的接管方会被赋值nil; -- 不匹配的发送方会被抛弃。 x, y, z = 1, 2, 3, 4 -- x = 1、y = 2、z = 3, 而 4 会被抛弃。 function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> 打印 "zaphod nil nil" -- 当初 x = 4, y = 8, 而值15..42被抛弃。 -- 函数是一等公民,能够是部分的,也能够是全局的。 -- 以下表达式等价: function f(x) return x * x end f = function (x) return x * x end -- 这些也是等价的: local function g(x) return math.sin(x) endlocal g; g = function (x) return math.sin(x) end-- 以上均因'local g',使得g能够自援用。local g = function(x) return math.sin(x) end-- 等价于 local function g(x)..., 但函数体中g不可自援用-- 顺便提下,三角函数以弧度为单位。 -- 用一个字符串参数调用函数,能够省略括号: print 'hello' --能够工作。 -- 调用函数时,如果只有一个table参数,-- 同样能够省略括号(table详情见下):print {} -- 一样能够工作。---------------------------------------------------- -- 3. Table。 ---------------------------------------------------- -- Table = Lua惟一的组合数据结构; -- 它们是关联数组。 -- 相似于PHP的数组或者js的对象, -- 它们是哈希表或者字典,也能够当列表应用。 -- 按字典/map的形式应用Table: -- Dict字面量默认应用字符串类型的key: t = {key1 = 'value1', key2 = false} -- 字符串key能够应用相似js的点标记: print(t.key1) -- 打印 'value1'. t.newKey = {} -- 增加新的键值对。 t.key2 = nil -- 从table删除 key2。 -- 应用任何非nil的值作为key: u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) -- 打印 "tau" -- 数字和字符串的key按值匹配的-- table按id匹配。 a = u['@!#'] -- 当初 a = 'qbert'. b = u[{}] -- 咱们或者期待的是 1729, 然而失去的是nil: -- b = nil ,因为没有找到。 -- 之所以没找到,是因为咱们用的key与保留数据时用的不是同-- 一个对象。 -- 所以字符串和数字是移植性更好的key。 -- 只须要一个table参数的函数调用不须要括号: function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} -- 打印'Sonmi~451'. for key, val in pairs(u) do -- 遍历Table print(key, val) end -- _G 是一个非凡的table,用于保留所有的全局变量 print(_G['_G'] == _G) -- 打印'true'. -- 按列表/数组的形式应用: -- 列表字面量隐式增加整数键: v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- #v 是列表的大小 print(v[i]) -- 索引从 1 开始!! 太疯狂了! end-- 'list'并非真正的类型,v 其实是一个table, -- 只不过它用间断的整数作为key,能够像list那样去应用。 ---------------------------------------------------- -- 3.1 元表(metatable) 和元办法(metamethod)。 ---------------------------------------------------- -- table的元表提供了一种机制,反对相似操作符重载的行为。-- 稍后咱们会看到元表如何反对相似js prototype的行为。 f1 = {a = 1, b = 2} -- 示意一个分数 a/b. f2 = {a = 2, b = 3} -- 这会失败:-- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) local sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sumendsetmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- 调用在f1的元表上的__add(f1, f2) 办法 -- f1, f2 没有对于元表的key,这点和js的prototype不一样。 -- 因而你必须用getmetatable(f1)获取元表。-- 元表是一个一般的table, -- 元表的key是一般的Lua中的key,例如__add。 -- 然而上面一行代码会失败,因为s没有元表: -- t = s + s -- 上面提供的与类类似的模式能够解决这个问题: -- 元表的__index 能够重载用于查找的点操作符: defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- 能够工作!感激元表 -- 如果在table中间接查找key失败,会应用-- 元表的__index 递归地重试。-- __index的值也能够是function(tbl, key)-- 这样能够反对自定义查找。 -- __index、__add等的值,被称为元办法。 -- 这里是一个table元办法的清单: -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b -- __index(a, b) <fn or a table> for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------------------------------------------------- -- 3.2 与类类似的table和继承。 ---------------------------------------------------- -- Lua没有内建的类;能够通过不同的办法,利用表和元表-- 来实现类。 -- 上面是一个例子,解释在前面: Dog = {} -- 1. function Dog:new() -- 2. local newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('I say ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- 'I say woof' -- 8. -- 1. Dog看上去像一个类;其实它是一个table。 -- 2. 函数tablename:fn(...) 等价于-- 函数tablename.fn(self, ...)-- 冒号(:)只是增加了self作为第一个参数。 -- 浏览7 & 8条 理解self变量是如何失去其值的。 -- 3. newObj是类Dog的一个实例。 -- 4. self = 被继承的类。通常self = Dog,不过继承能够扭转它。 -- 如果把newObj的元表和__index都设置为self, -- newObj就能够失去self的函数。 -- 5. 备忘:setmetatable返回其第一个参数。 -- 6. 冒号(:)的作用和第2条一样,不过这里 -- self是一个实例,而不是类 -- 7. 等价于Dog.new(Dog),所以在new()中,self = Dog。 -- 8. 等价于mrDog.makeSound(mrDog); self = mrDog。 ---------------------------------------------------- -- 继承的例子: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() local s = self.sound .. ' ' -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- 'woof woof woof' -- 4. -- 1. LoudDog取得Dog的办法和变量列表。 -- 2. 因为new()的缘故,self领有了一个'sound' key,参见第3条。 -- 3. 等价于LoudDog.new(LoudDog),转换一下就是 -- Dog.new(LoudDog),这是因为LoudDog没有'new' key, -- 然而它的元表中有 __index = Dog。 -- 后果: seymour的元表是LoudDog,并且 -- LoudDog.__index = Dog。所以有seymour.key -- = seymour.key, LoudDog.key, Dog.key -- 从其中第一个有指定key的table获取。 -- 4. 在LoudDog能够找到'makeSound'的key; -- 等价于LoudDog.makeSound(seymour)。 -- 如果有必要,子类也能够有new(),与基类类似: function LoudDog:new() local newObj = {} -- 初始化newObj self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. 模块 ---------------------------------------------------- --[[ 我把这部分给正文了,这样脚本剩下的局部能够运行 -- 假如文件mod.lua的内容相似这样: local M = {} local function sayMyName() print('Hrunkner') end function M.sayHello() print('Why hello there') sayMyName() end return M -- 另一个文件能够应用mod.lua的性能: local mod = require('mod') -- 运行文件mod.lua. -- require是蕴含模块的规范做法。 -- require等价于: (针对没有被缓存的状况;参见前面的内容) local mod = (function () <contents of mod.lua> end)() -- mod.lua被包在一个函数体中,因而mod.lua的局部变量-- 对外不可见。 -- 上面的代码能够工作,因为在这里mod = mod.lua 中的 M: mod.sayHello() -- Says hello to Hrunkner. -- 这是谬误的;sayMyName只在mod.lua中存在: mod.sayMyName() -- 谬误 -- require返回的值会被缓存,所以一个文件只会被运行一次, -- 即便它被require了屡次。 -- 假如mod2.lua蕴含代码"print('Hi!')"。 local a = require('mod2') -- 打印Hi! local b = require('mod2') -- 不再打印; a=b. -- dofile与require相似,然而不缓存: dofile('mod2') --> Hi! dofile('mod2') --> Hi! (再次运行,与require不同) -- loadfile加载一个lua文件,然而并不运行它。 f = loadfile('mod2') -- Calling f() runs mod2.lua. -- loadstring是loadfile的字符串版本。 g = loadstring('print(343)') --返回一个函数。 g() -- 打印343; 在此之前什么也不打印。 --]] 参考为什么?我十分兴奋地学习lua, 这样我就能够应用 Löve 2D 游戏引擎来编游戏。 ...

December 3, 2022 · 6 min · jiezi

关于lua:Unity移动端游戏性能优化简谱之-常见游戏内存控制

《Unity挪动端游戏性能优化简谱》从Unity挪动端游戏优化的一些根底探讨登程,例举和剖析了近几年基于Unity开发的挪动端游戏我的项目中最为常见的局部性能问题,并展现了如何应用UWA的性能检测工具确定和解决这些问题。内容包含了性能优化的根本逻辑、UWA性能检测工具和常见性能问题,心愿能提供给Unity开发者更多高效的研发办法和实战经验。 明天向大家介绍文章第二局部:资源内存、Mono堆内存等常见游戏内存管制,共13大节,蕴含了纹理资源、网格资源、动画资源、音频资源、材质资源等多个资源内存以及Mono堆内存等常见的游戏内存管制解说。(全文长约11400字,预计浏览工夫约20分钟) 文章第一局部《Unity挪动端游戏性能优化简谱之 前言》可戳此回顾,残缺内容可返回UWA学堂查看。 1. 总览1.1 概念解释首先,在探讨内存相干的各项参数和制订规范之前,咱们须要先理清在各种性能工具的统计数据中常呈现的各种内存参数的理论含意。 在安卓零碎中,咱们最常见到和关怀的PSS(Proportional Set Size)内存,其含意为一个过程在RAM中理论应用的空间地址大小,即理论应用的物理内存。就后果而言,当一个游戏过程中PSS内存峰值越高、占以后硬件的总物理内存的比例越高,则该游戏过程被零碎杀死(闪退)的概率也就越高。 而在PSS内存中,除了Unused局部外,咱们个别比较关心Reserved Total内存和Lua、Native代码、插件等零碎缓存、第三方库的本身调配等内存。Reserved Total占比个别较高,故其大小和走势,也是UWA性能剖析工具的次要统计对象(对于应用到Lua的我的项目,UWA另外提供了Lua专项测试报告统计Lua内存,下文还会提到)。 Reserved Total和Used Total为Unity引擎在内存方面的总体调配量和总体使用量。 一般来说,引擎在分配内存时并不是向操作系统 “即拿即用”,而是首先获取一定量的间断内存,而后供本人外部应用,待空余内存不够时,引擎才会向零碎再次申请一定量的间断内存进行应用。 留神:对于绝大多数平台而言,Reserved Total内存 = Reserved Unity内存 + GFX内存 + FMOD内存 + Mono内存 (1) Reserved Unity内存Reserved Unity和Used Unity为Unity引擎本身各个模块外部的内存调配,包含各个Manager的内存占用、序列化信息的内存占用和局部资源的内存占用等等。 通过针对大量我的项目的深度剖析,UWA发现导致Reserved Unity内存调配较大的起因次要有以下几种: 序列化信息内存占用:Unity引擎的序列化信息品种繁多,其中最为常见且内存占用较大的为SerializedFile。该序列化信息的内存调配次要是我的项目通过特定API(WWW.LoadFromCacheOrDownload、CreateFromFile等)加载AssetBundle文件所致。 资源内存占用:次要包含Mesh、AnimationClip、RenderTexture等资源。对于未开启“Read/Write Enable” 选项的Mesh资源,其内存占用是统计在GFX内存中供GPU应用的,但开启该选项后,网格数据会在Reserved Unity中保留一份,便于我的项目在运行时对Mesh数据进行实时的编辑和批改。同时,如果研发团队同样开启了纹理资源的 “Read/Write Enable” 选项(默认状况下为敞开),则纹理资源同样会在Reserved Unity中保留一份,进而造成其更大的内存占用。 (2) GFX内存 GFX内存为底层显卡驱动所反馈的内存调配量,该内存调配由底层显卡驱动所管制。一般来说,该局部内存占用次要由渲染相干的资源量所决定,包含纹理资源、Mesh资源、Shader资源传向GPU的局部,以及解析这些资源的相干库所调配的内存等。 (3) 托管堆内存托管堆内存示意我的项目运行时代码调配的托管堆内存调配量。对于应用Mono进行代码编译的我的项目,其托管堆内存次要由Mono调配和治理;对于应用IL2CPP进行代码编译的我的项目,其托管堆内存次要由Unity本身调配和治理。 1.2 内存参数规范在咱们理解了内存相干的各项参数的含意之后,晓得了防止游戏闪退的重点在于管制PSS内存峰值。而PSS内存的大头又在于Reserved Total中的资源内存和Mono堆内存。对于应用Lua的我的项目来说,还应关注Lua内存。 依据UWA的教训,只有当PSS内存峰值管制在硬件总内存的0.5-0.6倍以下的时候,闪退危险才较低。举例而言,对于2GB的设施而言,PSS内存应管制在1GB以下为最佳,3GB的设施则应管制在1.5GB以下。 而对于大多数我的项目而言,PSS内存大概高于Reserved Total 200MB-300MB左右,故2GB设施的Reserved Total应管制在700MB以下、3GB设施则管制在1GB以下。 特地的,UWA还认为Mono堆内存须要予以关注,因为在很多我的项目中,Mono堆内存除了存在自身驻留偏高或存在泄露危险的问题外,其大小还会影响GC耗时。UWA认为管制在80MB以下为最佳。 下表为UWA提供的细化到每一种资源内存的举荐规范,制订较为严格。不过,仍须要开发者依据本身我的项目的理论状况予以调整。比方某个2D我的项目节俭了简直所有网格资源的应用,那么其余资源的规范就能够放宽很多。 对于更多的细化规范,大家能够间接在UWA线上产品中进行对应查看。 基于我的项目实情制订内存规范后,个别需进一步与美术、策动协商,给出正当的美术标准参数,并撰写成文档。 定好标准后,定时查看我的项目里的所有美术资源是否符合规范,及时批改和更新。查看美术是否合规的过程,能够利用Unity提供的回调函数写自动化工具,提高效率。能够参考《自动化标准Unity资源的实际》。 如果资源若不能批量解决成高中低配版本,就须要美术为各个画质等级制作不同的资源。 1.3 本地资源检测服务-我的项目资源检测各项资源内存的引擎设置项繁琐且并不都能在运行时被采集,下文行将提到的内容尽管是泛滥我的项目中常见且重要的问题,但理论我的项目中的状况更加简单。通过本地资源检测服务的我的项目资源检测界面,往往能发现更多资源设置项的问题。它们不光影响相干资源的内存占用,还会依据状况对CPU耗时和GPU造成不同水平的压力。 为此UWA依据教训设计了检测规定和阈值,以此为根据采集和统计了存在这些问题的资源,并给出了对应的优化倡议,帮忙开发者针对资源进行更加深刻的排查和优化。 2. 常见的共通性问题这一部分提到的问题没有特定性,不仅仅呈现在一种资源内存中。所以,为了防止赘述,此处对立予以探讨。 ...

June 17, 2022 · 2 min · jiezi

关于lua:ToLua或XLua中的虚拟机是否独立于Unity的主线程

1)ToLua或XLua中的虚拟机是否独立于Unity的主线程2)Timeline技能编辑器提取关键帧信息3)Canvas AdditionalShaderChannels设置有效4)SDK返回的时候取Time.deltaTime比拟大 这是第291篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) LuaQ:ToLua或XLua中的虚拟机是否独立于Unity的主线程? A:Lua的虚拟机有本人的堆、栈内存,虚拟机的更新须要有内部的线程通过函数调用来驱动,而Lua虚拟机目前只反对单个线程来驱动。在理论我的项目中,因为Lua中要拜访Unity的API,所以基本上都是通过主线程来驱动。 但实际上,如果不须要拜访Unity API,齐全是能够放在子线程里去驱动的。 该答复由UWA提供 TimelineQ:最近在用Unity做一个技能编辑器,让策动能够在Timeline编辑器里编辑技能动画、施法特效、受击动画、受击特效和播放声音等等。编辑这些都没什么问题,我想依据编辑好的Timeline导出一系列行为节点,在Editor的环境下导出成配置(蕴含所有行为节点)。当初我不分明怎么获取Timeline里第m帧开始某动画x,第n帧完结这些行为。同时怎么能给动画打上对应Tag? A1:Timeline的组成如下图: 每个Track对应一个TrackAsset其实就是一个PlayableAsset,整个Timeline也是一个TimelineAsset,外面存了所有Track的数据。 对于每个Clip的开始和完结工夫在TimelineClip中能够获取。 感激羽飞@UWA问答社区提供了答复 A2:我把基于Timeline的编辑器小Demo共享上来。 技能编辑器Demo。 以上是自己摸索着写的一个简略技能编辑器Demo,基于Timeline的。 感激题主右前锋@UWA问答社区提供了答复 UGUIQ:在UI中应用到的Shader中用到了UV1和UV2通道,在Canvas AdditionalShaderChannels中抉择增加了对应通道后没有成果,雷同代码资源在2019.4.26f1c1正确显示,求教大家是否是版本问题还是须要非凡设置解决? Unity版本:2018.4.17f1 Unity版本:2019.4.26f1c1 A:搜寻了一下Unity Release Note,在Unity 2019.2.0版本中发现Unity修复了这个问题。修复后,AddVert会把UV2的数据和UV3的数据也拷贝进去。没修复前,UV2的数据从RenderDoc外面看是0。 测试了一下,的确在2019.1.14版本还是有问题的,下一个版本2019.2.0就没问题了。 在2018.4.23f1版本上参考这个链接的Outline成果进行了测试,在小米9真机上没有发现问题,题主能够参考一下:https://www.1024sou.com/artic... PS:看了2018.4.18到2018.4.23之间的所有的Release Note,没有发现相干问题的修复。这个文章是应用Shader来实现Outline的,感觉成果挺不错。 感激Xuan@UWA问答社区提供了答复 ScriptQ:nity调用某SDK进行登录,SDK返回的时候取Time.deltaTime比拟大(就是从调用SDK开始到SDK返回的工夫),这种状况可能导致我在Update里的逻辑经验了很长的一帧。 A1:间接点就是判断Time.deltaTime大于某个阈值时间接Return。感激碎心客@UWA问答社区提供了答复 A2:Time.deltaTime比拟大也就是说登录操作的耗时很高,而且是一个同步调用,的确会导致卡顿问题(在Update里的逻辑经验了很长的一帧)。<br/>一般来说,网络申请等操作应该尽可能通过异步调用来实现,如果是SDK的登录接口没有提供异步办法,倡议先尝试通过子线程(new Thread)来调用,而后主线程上开个协程每帧轮询下后果。该答复由UWA提供 封面图来源于网络 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:793972859(原群已满员)

March 28, 2022 · 1 min · jiezi

关于lua:APISIX单元测试准备工作与问题解决方案

最近电脑更新,换了M1的,所有工作从新开始,意味着APISIX插件开发之路中的绊脚石——单测环境筹备,也要从新筹备。 因为降级了芯片和最新的macOS零碎(12.2.1),导致过程并没有设想中的顺利,之前没遇到过的坑,一个个的裸露进去了,这里做一个分享和BackUp。 还有想吐槽一下APISIX官网的文档,在对于单元测试和插件编写方面的内容,输入不是特地的多,而且散落各处,着实给开发人员带来了麻烦。 以下的操作都是基于APISIX源码下操作(https://github.com/apache/apisix),写该文时版本为V2.12.1。失常装置流程装置各种环境依赖 # install OpenResty, etcd and some compilation tools brew install openresty/brew/openresty luarocks lua@5.1 etcd curl git pcre openldap cpanminus # start etcd server brew services start etcd官网最新源码中提供了脚本,位于utils/install-dependencies.sh。间接执行这个脚本就能够对上方的依赖进行装置和启动。 官网文档 批改环境变量结合实际装置状况批改.bash_profile文件,并别忘了 source ~/.bash_profile。 OPENRESTY_HOME=/usr/local/openrestyPATH=$OPENRESTY_HOME/nginx/sbin:$OPENRESTY_HOME/bin:$PATHexport OPENRESTY_HOME下载APISIX源码git clone https://github.com/apache/apisix.git源码环境下解决# 源码根目录下git clone https://github.com/iresty/test-nginx.gitrm -rf test-nginx/.gitsudo cpanm --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)export PERL5LIB=.:$PERL5LIBmake deps我看官网举荐应用 make deps ENV_LUAROCKS_SERVER=https://luarocks.cn,但我试了,并没有起效,仍旧应用 https://luarocks.org,起初我通过批改luarocks配置文件 ~/.luarocks/config-5.1.lua ,失效了,大家也能够本人试试,在文章下方做个反馈。 APISIX文档 rocks_servers = { "https://luarocks.cn"}因为github的网络起因,make deps过程可能不是一帆风顺,有点急躁多试几次就能够了。 ...

March 9, 2022 · 2 min · jiezi

关于lua:AssetBundle异步加载被中断的问题

1)AssetBundle异步加载被中断的问题2)LuaDLL.lua_pcall()本身产生开销问题3)法线在手机渲染时呈现的谬误问题4)UNITY_MATRIX_I_V 和Camera.main.worldToCameraMatrix.inverse区别 这是第272篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) ResourcesQ:在应用异步接口yield return AssetBundle.ASyncLoad的时候,难免会想到:这个异步解决完之前如何Cancel掉这个工作?也就是说一个AssetBundle加载到一半,当初要放弃加载,应该怎么解决? A1:其实底层调用GetAssetBundleBlocking,会在这个函数外部调用PreloadManager的加载更新逻辑,其实就是把Async操作改成了Sync了,会始终阻塞到AssetBundle加载胜利。 然而也有坑,这儿因为执行了PreloadManager.UpdatePreloading,外部还会做GC。遇到过把不应该卸载的资源给卸载了,说是Unused,然而理论正在应用。 感激黄程@UWA问答社区提供了答复 A2:资源加载治理的第一难题就是异步IO怎么被Cancel掉,或者说从设计上怎么去实现等同的成果。 然而绝对于从Flash到Cocos到Unity来说,Unity还是做的很好的。之前的任何引擎要解决好这个问题,十分之艰难,须要很多代码的反对,包含多线程更低层次的相干代码。这一块Unity做得十分好,咱们不必搜索枯肠去实现异步IO Cancel的问题,只须要做好下层架构,设计出相似的性能。 Unity的异步加载会返回一个Request对象,该对象有一个Get属性AssetBundle,认真查看该Get函数API会发现。当调用该属性时,会促使底层异步IO中断(具体怎么实现的,有C++源码的能力晓得),并立刻同步加载该资源,且回调,回调程序是和你调用程序相当的(比方异步加载调用了2次并设置了回调,当初触发中断并立刻实现,会优先回调异步设置的回调)。 所以基于这个设计一个好的援用计数器治理资源十分重要。 大部分我的项目的援用计数器设计都是待资源实现后增加援用计数。这种设计的实用场景十分局限。在大型项目中应用环境非常复杂的资源加载状况下(异步加载中调用同步,异步加载中须要勾销,异步加载中勾销后立刻同步等)会呈现十分多的未知问题和开发中的局限性,这种设计只适宜微型我的项目疾速开发。 所以一个齐备的援用计数设计应该是调用加载办法时,就生成该资源将来被加载实现后的数据壳子,并增加援用计数(因为加载自身其实也是一次援用,包含bundle.AsynLoadAsset,其实任何的异步加载本身都须要增加一次援用,避免下层代码的逻辑,造成援用计数器非法=0触发bundle.unload办法),实现后缩小援用计数。那么同步加载时须要查找数据壳子,如果该资源正在异步加载,须要调用其request.assetBundle让其立刻中断异步并立刻同步实现加载。(否则同步加载时底层会抛出正告。) 基于这个咱们能够设计一套十分齐备的Cancel零碎,下层调用Cancel时,其实就是让其内部援用-1,因为实践上咱们能拿到的所有接口无奈真正中断一次IO,只有待其加载实现后,发现援用计数等于0时,才会Unload掉资源。 设计思路这里只是抛出一点,具体怎么去实现和设计畅所欲言。只是如果一个资源管理器不能适应任何(绝大部分)加载情景,那么这还是一个资源管理器吗? 感激1 9 7 3-311135@UWA问答社区提供了答复 LuaQ:为什么LuaDLL.lua_pcall()本身会产生这么大的开销? A1:是不是Lua本身逻辑耗费比拟高,这个能够看Lua侧的耗费:《Lua Profiler——疾速定位Lua性能问题》。感激jjjzzz@UWA问答社区提供了答复 A2:lua_pcall只是通过压栈的形式调用了Lua,具体耗费还得在Lua那边看看,预计是某函数C#和Lua疯狂调用比拟厉害。 感激萧小俊@UWA问答社区提供了答复 A3:用DeepProfile能力晓得具体是哪个办法调用高,这里只是C# call到Lua,前面的栈信息曾经没有了,不能单纯的说LuaDLL.lua_pcall()开销大。感激1 9 7 3-311135@UWA问答社区提供了答复 RenderingQ:法线在手机渲染时呈现的谬误问题:用的版本是Unity 2019.4 URP。Editor模式下是正确的,在默认Unity Build的打包正确,将资源打成AssetBundle后渲染呈现谬误。Shader应用了多种,包含默认的Lit Shader,都会呈现该问题。 A:狐疑是渲染管线的Shader问题,变体收集问题,最初一一排除后变成Mesh问题。有好大哥MoMo的奶爸通知我,Unity局部版本的Optimize Mesh Data选项默认关上,会优化掉局部网格,导致以上的问题。感激题主霸气九号@UWA问答社区提供了答复 RenderingQ:URP中Shader的UNITY_MATRIX_I_V 和C#中Camera.main.worldToCameraMatrix.inverse获取到的矩阵并不一样,在Shader中用ViewSpace的坐标乘以UNITY_MATRIX_I_V并不可能失去正确的世界坐标,乘以Camera.main.worldToCameraMatrix.inverse则能够,请问他们二者的区别是什么呢? A:我这边做的测试并没有发现这两个矩阵有什么不同。 fixed4 frag (v2f i) : SV_Target{ fixed4 col = UNITY_MATRIX_I_V[0]; return col;}在Shader中批改Frag来调用UNITY_MATRIX_I_V: void Start(){ Debug.Log(Camera.main.cameraToWorldMatrix); Debug.Log(m_camera.cameraToWorldMatrix); Debug.Log(Camera.main.worldToCameraMatrix.inverse);}在C#中打印这个矩阵,从Frame Debugger和控制台输入的后果来看这两个矩阵没有什么不同。 应用URP的Shader Simple Lit,计算逆矩阵之后的后果也是统一的: 感激宗卉轩@UWA问答社区提供了答复 ...

November 1, 2021 · 1 min · jiezi

关于lua:mac上安装lua

一、背景最近在操作redis的时候,有些时候是须要原子操作的,而redis中反对lua脚本,因而为了当前学习lua,此处记录一下 lua的装置。 二、mac上装置lua其余的零碎上装置lua步骤大略类似。 1、拜访lua下载页面拜访 lua下载链接 https://www.lua.org/download.html 2、通过源码装置lua1、下载luacurl -R -O http://www.lua.org/ftp/lua-5.4.3.tar.gz2、解压tar -zxvf lua-5.4.3.tar.gz3、进入lua目录cd lua-5.4.34、执行make命令make执行make命令,如果make出错,参考make出错的解决执行完make命令后在咱们的src目录下会存在lua、luac和liblua.a文件 5、检测lua是否构建正确$ make test ./lua -vLua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio输入了版本号阐明是构建正确的 6、装置lua $ sudo make all install Password:Guessing Darwin/Library/Developer/CommandLineTools/usr/bin/make all SYSCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" SYSLIBS="-lreadline"make[3]: Nothing to be done for `all'.cd src && mkdir -p /usr/local/bin /usr/local/include /usr/local/lib /usr/local/man/man1 /usr/local/share/lua/5.4 /usr/local/lib/lua/5.4cd src && install -p -m 0755 lua luac /usr/local/bincd src && install -p -m 0644 lua.h luaconf.h lualib.h lauxlib.h lua.hpp /usr/local/includecd src && install -p -m 0644 liblua.a /usr/local/libcd doc && install -p -m 0644 lua.1 luac.1 /usr/local/man/man1如果没有权限就加上sudo ...

October 20, 2021 · 1 min · jiezi

关于lua:不会-LuaPython-助你快速上手-Apache-APISIX-插件开发

相熟 Apache APISIX 的小伙伴都晓得,之前在社区中咱们曾经反对了 Java 和 Go 语言的 Runner,明天 Apache APISIX Python Runner 也来了,社区中的小伙伴们在开发 Apache APISIX 插件时又多了一种新抉择。 Python 语言作为一个解释型的高级编程语言,它语法简洁易上手、代码可读性好 ,在跨平台 、可移植性 、开发效率上都有很好的体现,同时作为一个高级编程语言它的封装形象水平比拟高屏蔽了很多底层细节(例如:GC )让咱们在开发的过程中能够更专一应用逻辑的开发。 同时作为一个有 30 年历史的老牌开发语言,它的生态以及各种模块曾经十分欠缺,咱们大部分的开发和利用场景都能够从社区中找到很成熟的模块或解决方案。 Python 其余的长处就不再一一赘述,当然它的毛病也比拟显著:Python 作为一门解释性语言,相较于 C++ 和 Go 这样的编译型语言,在性能上的差距还是比拟大的。 理解:我的项目架构apache-apisix-python-runner 这个我的项目能够了解为 Apache APISIX 和 Python 之间的一道桥梁,通过 Python Runner 能够把 Python 间接利用到 Apache APISIX 的插件开发中,最重要的还是心愿让更多对 Apache APISIX 和 API 网关感兴趣的 Python 开发者通过这个我的项目,更多地理解和应用 Apache APISIX,以下为 Apache APISIX 多语言反对的架构图。 上图右边是 Apache APISIX 的工作流程,左边的 Plugin Runner 是各语言的插件运行器,本文介绍的 apisix-python-plugin-runner 就是反对 Python 语言的 Plugin Runner。 ...

September 16, 2021 · 2 min · jiezi

关于lua:关于AI逻辑写在Lua中的问题

1)对于AI逻辑写在Lua中的问题2)Shader中宏的作用3)Update中的new Struct对象4)通过在编辑的预制体中获取资源门路 这是第266篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) LuaQ:当初战斗的外围逻辑都在xLua外面,蕴含了AI的逻辑,这部分计算量极大,会造成画面卡死。 尝试过用Thread把xLua虚拟机包一层,后果还是会报Main Thread的谬误。也尝试用闭包的形式,从Lua回传到CSharp,用System.Action接住,而后丢线程外面跑,然而会卡断主线程。 当初想尝试用两个Lua虚拟机,一个放Thread外面只跑战斗,其余的放在主Lua虚拟机中。那么整个游戏运行起来,会有3个虚拟机:Mono、xLua和xLuaInThread。 策动心愿AI做得聪慧一些,对应的思考维度和运算量都会大幅提高。不晓得是否有其余举荐的计划? A1:我感觉不是虚拟机方向的问题: Lua和Unity交互的细节没有把控好,比方重复在lua.transform.position等等相似的。不论是Tolua还是xLua,并不是说齐全就不必C#了。应该是基于几个准则:扩展性、热更性和性能,比方MMORPG的头顶UI必定不是全副是Lua开发的,业务在Lua然而挪动那些必定是C#(一旦做完了,接下来简直不会再动到C#代码了)。Lua和C#交叉的细节须要把控。Lua自身的应用细节也须要把控好。感激沈杰@UWA问答社区提供了答复 A2:不须要多个虚拟机。能够浏览《游戏编程精粹》里的这两篇文章(年代有点久了不记得是哪一本,也不记得具体讲了那些内容,只是取得了思路后,本人实现过): 用于游戏对象AI的微线程应用微线程治理AI我在已经的我的项目中实现基于协程的工作管理器,大抵有这些特点: 每个游戏对象运行的脚本在独立创立的协程上。每个协程入口对立采纳相似C语言的入口办法标准,如: 入口函数Main。随眠函数Sleep,Yield,Waitframe,Waittime(这些办法能够准确管制AI的计算频率与精度)。退出相干办法Exit,Atexit。对立在宿主程序中,对游戏中多个协程进行按需调度,比方期待指定工夫,帧数后调用Resume唤醒协程。感激lujian@UWA问答社区提供了答复 ShaderQ:Particle Additive Shader中应用了该宏:UNITY\_DECLARE\_DEPTH\_TEXTURE(\_CameraDepthTexture);,查了一下没找到相干阐明。字面了解是申明了一个深度图。 在默认管线(向前渲染)中,依照惯例了解深度图须要通过设置Camera的depthTextureMode来指定。还请各位指教。 A:Shader中很多宏确实是没有官网阐明的,咱们须要去CGInclude文件夹中寻找其确切定义。 UNITY_DECLARE_DEPTH_TEXTURE在HLSLSupport.cginc里: 确实是为了申明一张图,回到Particle Add.shader中发现是为了申明深度图: 这是为了在片元着色器中的深度采样做筹备: 该SAMPLE_DEPTH_TEXTURE_PROJ办法同样在HLSLSupport.cginc中: 而后持续在该文件中找tex2Dproj: 由此可见这些操作就是在相机保留的深度图中,通过tex2D获取了深度,为LinearEyeDepth筹备参数从而失去场景深度。该Shader通常在开了软粒子之后被用到。 感激翟孟飞@UWA问答社区提供了答复 ScriptQ:Struct中蕴含String字段,如果在Update中new,会不会有GC问题?思考是否须要用缓存池来解决,目前我测试了一下将Struct改成Class是必定有,如果是Struct类型,就没找到。 A1:对Class进行new是会调配堆内存,然而这个堆内存不肯定是String字段造成的。Class的实例自身就会占用堆内存,而它的字段会不会造成堆内存调配,取决于new的时候会不会对类型进行实例化。实例化的时候给String赋值,如果是间接确定的字符串内容,编译器会主动进行缓存优化,只会在第一帧创立字符串分配内存。 至于Struct,构造体作为值类型自身不会占用堆内存。对Struct进行new会不会调配堆内存,取决于new的时候,它的字段会不会实例化,会不会占用堆内存。如果Struct没有写构造函数,即便外面有援用类型,在new Struct的时候也不会实例化,不会调配堆内存。如果写了构造函数,就要看构造函数外面是否调配堆内存了。String的状况与上文提到的统一。 感激Prin@UWA问答社区提供了答复 A2:C#语法中除了构造函数造成的堆内存调配,还有构造体对外传递造成栈上逃逸问题。具体表现是结构的构造体作用域不仅局限在Update函数内。 在Unity的Playable模块里能够见到大量的ref Struct签名,是C# 7里专门解决栈逃逸的语法,依葫芦画瓢即可。 感激陈xx@UWA问答社区提供了答复 ScriptQ:我想调用AssetDatabase.GetAssetPath 获取资源门路,但我点击图1物体,应用AssetDatabase.GetAssetPath(gameObject),却获取不到。想请问:如何通过图1获取到图2对应的物体门路? A1:PrefabUtility.GetNearestPrefabInstanceRoot用来获取最近的预制体实例;Root PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot用来获取预制体门路。 [MenuItem("Tools/GetPrefabInstancePath")] public static void GetPrefabInstancePath() { if (null != Selection.activeGameObject) { if (PrefabUtility.IsPartOfPrefabInstance(Selection.activeGameObject)) { var path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(Selection.activeGameObject); Debug.Log("Prefab Path:" + path); } } }感激马三小伙儿@UWA问答社区提供了答复 ...

September 13, 2021 · 1 min · jiezi

关于lua:Air302-关于-pmHIB-的休眠定时唤醒

合宙 Air302 模组应用中国移动 NB 卡 cmnbiot2 模板时, T3324 (activeTime) 不为 0 引起的休眠唤醒问题 (对于模组想尽快进入低功耗休眠状态时的利用场景) 对于 PSM 的阐明(尤其 T3324) 问题复现 : 当应用以下代码会呈现意料之外休眠和唤醒,导致无奈实现精准的休眠唤醒PROJECT = "lowpower"VERSION = "1.0.0"_G.sys = require("sys")sys.taskInit(function() log.info("===========================", "pm", "lastReson", pm.lastReson()) while not nbiot.isReady() do sys.wait(100) end log.info("--------------------------------------- begin") pm.dtimerStart(0, 5 * 60 * 1000) pm.request(pm.HIB) if pm.check() then log.info("pm", "it is ok to hib") end log.info("--------------------------------------- end")end)sys.run()意外的唤醒: luat.pm Go into Sleep2luat.pm poweron: Wakup Sleep2 by RTC 255 初步解决 : 在代码中设置 TAU 为 0, nbiot.setPSM(1, 86400, 0) (模组设置基站核心网 T3324 工夫)PROJECT = "lowpower"VERSION = "1.0.0"_G.sys = require("sys")sys.taskInit(function() nbiot.setPSM(1, 86400, 0) -- 留神这里!! log.info("===========================", "pm", "lastReson", pm.lastReson()) while not nbiot.isReady() do sys.wait(100) end log.info("--------------------------------------- begin") pm.dtimerStart(0, 5 * 60 * 1000) pm.request(pm.HIB) if pm.check() then log.info("pm", "it is ok to hib") else log.info("pm", "force to hib") pm.force(pm.HIB) end log.info("--------------------------------------- end")end)sys.run()模组第一次上电或复位运行驻网,【可能会进入一次 `luat.pm Go into Sleep2` 、`luat.pm poweron: Wakup Sleep2 by RTC 255`】 之后再次进入`luat.pm Go into Hib`,尔后模组才将依照唤醒工夫准时唤醒(模组首次驻网设置 T3324 未失效)最终解决 : SIM 卡管理平台设置 T3324 为 0 [Net 状态指示灯燃烧不再闪速] ...

September 8, 2021 · 1 min · jiezi

关于lua:Lua与C传参

1)Lua与C#传参2)Unity公布iOS版本呈现屏幕问题3)安卓的View成为Unity界面的一部分4)Unity降级导致我的项目启动工夫过长5)Unity中Cascaded Shadows在挪动端的设置 这是第258篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) LuaQ:游戏中是先在Lua中String.format好再传入C#,还是在Lua里把参数传入C#,在C#里用String.format好? 即一个是Lua加载文字表,String.format后传给C#显示,另一个是C#读表,Lua把参数传给C#,再string.format应用,哪个形式更好些,或者有没有其余更好的形式? A1:搬运群里大佬的问答:第二种比拟好,因为传参越简略越好,参数能够打包传。感激Tao@UWA问答社区提供了答复 A2:能够参考一下这篇文章:《用好Lua+Unity,让性能飞起来——Lua与C#交互篇》,总之Lua与C#传参,优先思考int、float和double等类型,其次bool、string及object等类型,同时尽可能升高交互次数。感激羽飞@UWA问答社区提供了答复 iOSQ:Unity公布iOS版本在iOS 11之后呈现屏幕显示问题:半屏被压缩,另一半黑屏。 A:间接在编辑器中设置这几个参数,不要在代码中设置这个,7p就不会呈现这个问题:Screen.autorotateToLandscapeLeft = true; Screen.autorotateToLandscapeRight = true; Screen.autorotateToPortrait = false; Screen.autorotateToPortraitUpsideDown = false; Screen.orientation = ScreenOrientation.AutoRotation;感激许家胜@UWA问答社区提供了答复 UnityQ:加载了一个安卓的Activity,会遮挡住Unity的界面,如何让安卓的View,成为Unity界面的一部分呢?Unity界面的一部分应用安卓原生SDK的界面实现。 A:安卓混合Unity的界面,曾经实现了。https://blog.csdn.net/Yzw_92_...感激题主韩飞@UWA问答社区提供了答复 EditorQ:查看了Unity的editor.log发现外面: RefreshInfo: InitialScriptRefreshV2(NoUpdateAssetOptions)RefreshProfiler: Total: 0.000msInvokeBeforeRefreshCallbacks: 1115393.587ms...... OnSourceAssetsModified: 340.325ms...... ImportAndPostprocessOutOfDateAssets: 1032441.185ms (82533.117ms without children)ImportManagerImport: 82501.381ms (0.000ms without children)...... 有没有大佬晓得这个是在解决什么货色?迷信上网了也没有查到相干信息,这里看耗时就很长时间了1115393.587ms。 A:参考以下几点: 检查一下我的项目是不是放在机械硬盘上,倡议放NVME的固态上。因为高版本的数据结构更简单了,不必固态来不及序列化。检查一下是不是开了PlasticSCM。感激萧小俊@UWA问答社区提供了答复 RenderingQ:Unity的Shadow Cascade性能在挪动平台中是否失效? 在场景应用了Unity自带的实时暗影,具体参数如下: 用Frame Debug察看暗影绘制过程: Shadowmap为1024*1024,场景远处会有彩色的暗影笼罩。当Cascade设置为2则远处暗影隐没: 用Frame Debug察看暗影绘制过程: Shadowmap还是1024*1024,但一分为二,各占1024*512。 以上是在PC上验证的,证实Cascade的确起作用。但当在Unity编辑器中的BuildSettings中切换到Android平台时,无论怎么批改Cascade的值,场景远处均有暗影,用Frame Debug察看暗影绘制过程如下: 仿佛在安卓平台中这个参数不起作用,查阅Unity官服文档也并没阐明Shadow Cascade不反对挪动平台。 请问有同样遇到这种问题的吗? A:Graphics设置那里须要在对应的Tier外面启用Cascaded Shadows。感激题主x21@UWA问答社区提供了答复 20210712更多精彩问题等你答复~ 1.如何实现AAB包的增量更新2.对于Unity出AAB包的问题3.RTS 手游技术难点 封面图来源于网络 ...

July 19, 2021 · 1 min · jiezi

关于lua:LuaJIT-是如何工作的-JIT-模式

上一篇 咱们说到,JIT 是 LuaJIT 的性能杀手锏。这篇咱们就介绍一下 JIT。 Just-in-time 即时编译技术,在 LuaJIT 里的具体应用是:将 Lua byte code 即时编译为机器指令,也就是不再须要解释执行 Lua bytecode,间接执行即时编译产生的机器指令。也就是说,解释模式,和 JIT 模式的输出源是一样的,都是 Lua byte code。雷同的字节码输出,两种模式却能够有跑出显著的性能区别(一个数量级的区别,也是比拟常见的),这个还是很须要功力的。 JIT 能够分为这么几个步骤: 计数,统计有哪些热代码录制,录制热代码门路,生成 SSA IR code生成,SSA IR code 优化生成机器指令执行新生成的机器指令JIT 编译对象在进一步开展之前,先介绍一个基本概念。LuaJIT 的 JIT 是基于 trace 的,意味着一段 byte code 执行流,而且是能够逾越函数的。相比较而言,Java 的 JIT 是基于 method 的,尽管也有函数内联,然而限度比拟大(只有很小的函数才会被内联 JIT 编译)。 集体认为,tracing JIT 在实践上来说,能够比 method base JIT 有更大的施展空间,如果只是某些 case 跑分,应该能够更厉害。不过工程实现复杂程度要高不少,所以最终的理论工业成果,也难说(影响 JIT 成果的,还有很多其余因素,比方优化器等等)。 比方这个小示例: local debug = falselocal function bar() return 1endlocal function foo() if debug then print("some debug log works") end return bar() + 1end当 foo() 函数被 JIT 编译的时候,有两个显著的长处: ...

June 23, 2021 · 2 min · jiezi

关于lua:Lua-代码是如何跑起来的

上一篇「C 代码是如何跑起来的」中,咱们理解了 C 语言这种高级语言是怎么运行起来的。 C 语言尽管也是高级语言,然而毕竟是很 “古老” 的语言了(快 50 岁了)。相比较而言,C 语言的抽象层次并不算高,从 C 语言的表达能力里,还是能够领会到硬件的影子。 旁白:通常而言,抽象层次越高,意味着程序员的在编写代码的时候,心智累赘就越小。明天咱们来看下 Lua 这门绝对小众的语言,是如何跑起来的。 解释型不同于 C 代码,编译器将其间接编译为物理 CPU 能够执行的机器指令,CPU 执行这些机器执行就行。 Lua 代码则须要分为两个阶段: 先编译为字节码Lua 虚拟机解释执行这些字节码旁白:尽管咱们也能够间接把 Lua 源码作为输出,间接失去执行输入后果,然而实际上外部还是会别离执行这两个阶段字节码在「CPU 提供了什么」 中,咱们介绍了物理 CPU 的两大根底能力:提供一系列寄存器,能执行约定的指令集。 那么相似的,Lua 虚拟机,也同样提供这两大根底能力: 虚构寄存器执行字节码旁白:Lua 寄存器式虚拟机,会提供虚构的寄存器,市面上更多的虚拟机是栈式的,没有提供虚构寄存器,然而会对应的操作数栈。咱们来用如下一段 Lua 代码(是的,逻辑跟上一篇中的 C 代码一样),看看对应的字节码。用 Lua 5.1.5 中的 luac 编译能够失去如下后果: $ ./luac -l simple.luamain <simple.lua:0,0> (12 instructions, 48 bytes at 0x56150cb5a860)0+ params, 7 slots, 0 upvalues, 4 locals, 4 constants, 1 function 1 [4] CLOSURE 0 0 ; 0x56150cb5aac0 2 [6] LOADK 1 -1 ; 1 # 将常量区中 -1 地位的值(1) 加载到寄存器 1 中 3 [7] LOADK 2 -2 ; 2 # 将常量区中 -2 地位的值(2) 加载到寄存器 1 中 4 [8] MOVE 3 0 # 将寄存器 0 的值,挪到寄存器 3 5 [8] MOVE 4 1 6 [8] MOVE 5 2 7 [8] CALL 3 3 2 # 调用寄存器 3 的函数,寄存器 4,和寄存器 5 作为两个函数参数,返回值放入寄存器 3 中 8 [10] GETGLOBAL 4 -3 ; print 9 [10] LOADK 5 -4 ; "a + b = " 10 [10] MOVE 6 3 11 [10] CALL 4 3 1 12 [10] RETURN 0 1function <simple.lua:2,4> (3 instructions, 12 bytes at 0x56150cb5aac0)2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions 1 [3] ADD 2 0 1 # 将寄存器 0 和 寄存器 1 的数相加,后果放入寄存器 2 中 2 [3] RETURN 2 2 # 将寄存器 2 中的值,作为返回值 3 [4] RETURN 0 1略微解释一下: ...

May 3, 2021 · 2 min · jiezi

关于lua:Lua-OpenResty容器化考古历程

原文地址:Lua OpenResty容器化(考古历程) 背景公司有几个“远古期间”的我的项目,始终都绝对较为稳固,然而我的项目每天总会在一些时段,申请每分钟QPS达到峰值800K左右,导致机器的性能呈现了一些瓶颈,每到峰值期间,总会呈现一个告警,切实是令人头疼。更蹩脚的是这只是远古期间我的项目中的其中一个而且都是部署在物理机器上,所有机器加起来靠近100台。 出于稳定性(削峰)和老本的角度思考,咱们最终决定将所有的Lua OpenResty我的项目上到k8s集群。 抉择适合的openresty根底镜像通过查看线上在应用的openresty版本信息: /usr/local/openresty/nginx/sbin/nginx -Vnginx version: openresty/1.13.6.2built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)built with OpenSSL 1.1.0h 27 Mar 2018 (running with OpenSSL 1.1.0k 28 May 2019)TLS SNI support enabledconfigure arguments: --prefix=/usr/local/openresty/nginx ...lua -vLua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio得悉在应用的是openresty/1.13.6.2和Lua 5.1.4 : docker pull openresty/openresty:1.13.6.2-2-centosQ:能不能抉择应用更小的alpine系列的呢? A:因为我的项目依赖许多的so库,都是glibc编译的,alpine的话是musl-lib,不兼容。 Q:为啥不从新编译? A:一方面是危险问题,另外一方面是有一些so库不肯定能找到。 查找我的项目的动静库依赖关系Nginx配置文件$ tree -L 3 nginx/confnginx/conf├── vhosts/│ ├── inner.prometheus.nginx.conf│ └── project.nginx.conf└── nginx.conf自编译的C动静库文件,如binary_protocol.so编写好dockerfile,而后将我的项目打包进容器,执行: /usr/local/openresty/nginx/sbin/nginx nginx -t果不其然,报错: /usr/local/openresty/nginx/lua/init.lua:1: module 'binary_protocol' not found:no field package.preload['binary_protocol']no file '/usr/local/openresty/nginx/lua/binary_protocol.lua'no file '/usr/local/openresty/nginx/lua_lib/binary_protocol.lua'no file '/usr/local/openresty/nginx/luarocks/share/lua/5.1/binary_protocol.lua'no file '/usr/local/openresty/site/lualib/binary_protocol.ljbc'…… ……no file '/usr/local/openresty/nginx/luarocks/lib64/lua/5.1/binary_protocol.so'no file '/usr/local/openresty/site/lualib/binary_protocol.so'no file '/usr/local/openresty/lualib/binary_protocol.so'no file '/usr/local/openresty/site/lualib/binary_protocol.so'no file '/usr/local/openresty/lualib/binary_protocol.so'no file './binary_protocol.so'no file '/usr/local/lib/lua/5.1/binary_protocol.so'no file '/usr/local/openresty/luajit/lib/lua/5.1/binary_protocol.so'no file '/usr/local/lib/lua/5.1/loadall.so'no file '/usr/local/openresty/luajit/lib/lua/5.1/binary_protocol.so'Q:仔细观察,发现so动静库是外部编译进去提供给lua调用的,如何找到它们呢? ...

April 21, 2021 · 2 min · jiezi

关于lua:lua远程调试-Remote-Debug

原文地址:lua近程调试 Remote Debug 日常的debug当把一个本地我的项目部署到近程测试服务器后有可能呈现意想不到谬误,为了排查问题可能会变成: 这样: 而后这样: 最初就: 最可怕的是,因为堆栈的关系,很难在一次debug日志中拿到想要的信息,往往是一层层往下打日志,能力拿到想要的debug信息。 remote debug本地服务器凋谢端口,将近程服务器的断点信息打到本地服务器。 那具体如何实现呢?jetbrains的“EmmyLua”插件 + mobdebug库 本地jetbrains减少EmmyLua插件装置 远端服务器减少mobdebug包放到我的项目debug目录下,并减少配置信息https://github.com/pkulchenko... local mobdebug = require("debug.mobdebug");mobdebug.rbasedir("/usr/local/openresty/nginx/lua/") -- remotemobdebug.lbasedir("/Users/wilburxu/lua/test/") -- localmobdebug.start("host.docker.internal", 28172); ps:断点信息发回的是远端服务器的line,所以本地服务器要保障和远端服务器的line统一。 本地增加调试configuration 发送申请就能够失去咱们想要的堆栈信息了。 MobDebug的根本构造mobdebug是一个纯lua实现的近程调试器,依赖于luasocket,根本的通信形式是应用字符串的形式在目标程序和IDE之间传输相应的控制指令和执行后果,mobdebug与远端交互的数据是间接包装成Lua格局的字符串的。 交互协定mobdebug应用的通信模式是应答式的,也就是大部分时候都是远端的IDE向调试目标程序发送一条命令后,就进入期待调试指标返回后果的状态了,在EmmyLua源代码侧的体现就是保护了一个Command队列,如果Command是须要应答的,那只有以后Command被解决完后,才会接着发送队列中残余的Command。

April 20, 2021 · 1 min · jiezi

关于memory:下载AssetBundle的Mono内存问题

1)下载AssetBundle的Mono内存问题2)Unity 2019运行时获取Hierarchy上预制体资源门路3)多个Submeshes模型合并后的显示问题4)ToLua中拜访Time.deltaTime为05)CacheServer莫名的断开连接 这是第242篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) MemoryQ:应用协程+UnityWebRequest下载Bundle时调配的内存开释不掉。 下载步骤如下:1. 应用协程+UnityWebRequest下载Bundle;2. 应用BinaryWriter将UnityWebRequest.downloadHandler.data的数据写入机器;3. 调用UnityWebRequest的Dispose函数;4. 调用Resources.UnloadUnusedAssets(),UnityWebRequest.ClearCookieCache()和System.GC.Collect()。 下载每一个Bundle都会执行如上流程,然而Profiler调试真机发现,调配的内存无奈开释,会把Mono内存越撑越大,请问大家遇到过这种状况吗? A:之前遇到过相似的问题,题主能够参考一下,咱们应用的Unity版本是2018.4.31。不论是之前的WWW还是当初的WebRequest,都是应用的其成员DownloadHandler进行下载。当你拜访“.data”属性时,其实拜访的是一个“GetData()”函数的包装,这个函数返回的是一段native-memory data buffer的拷贝,这也是问题的根结所在。 第一个能够优化的点就是缩小“.data”的应用,用长期变量缓存下来。第二个就是替换DownloadHandler,Unity提供了多种DownloadHandler,咱们过后是下载图片,所以用的是DownloadHandlerTexture,看你的问题,能够试试DownloadHandlerAssetBundle。 参考:https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAssetBundle-ctor.html 感激Joke@UWA问答社区提供了答复 EditorQ:美术心愿在编辑器运行的状态下获取场景GameObject实例对应预制体的门路,以前Unity 2017是能够通过var pRoot = PrefabUtility.GetPrefabParent(go); return AssetDataBase.GetAssetPath(pRoot),获取运行时预制门路的。 最近降级到2019发现接口曾经更新,PrefabUtility.GetPrefabInstanceHandle(targetGameObject)、PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)等接口都不能在Unity运行的时候去获取Hierarchy外面的GameObject门路。 我问题外面的要害是运行状态,也就是点了播放,而后获取Hierarchy上预制的存储门路。PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)不点播放是能够获取,播放了只能获取Project上预制的存储门路。 A:PrefabUtility.GetNearestPrefabInstanceRoot:获取最近的预制体实例Root。PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot:获取预制体门路。 if (PrefabUtility.IsPartOfPrefabInstance(seletedGo)){ string prefabAssetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(seletedGo);} GetPrefabAssetPathOfNearestInstanceRoot能够获取门路,“PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)” 这个接口传的不是Prefab局部,而是实例的。 如果不行,在Editor时,在它身上挂脚本或者别的形式建设映射,Runtime下再拿。 感激静风霁@UWA问答社区提供了答复 MeshQ:求教下,我测试一个Skinmesh合并性能,发现当Mesh蕴含多个Submeshes时,合并胜利后,无奈渲染显示进去。 当测试的Mesh不蕴含Submeshes时,能够合并显示。难道CombineMeshes只能合并不带Submeshes的Mesh?不晓得问题出在哪?有什么解决思路吗? 注:不论是应用“r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false); ”带上所有材质,还是“r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false) ;”合并一张贴图材质,带多个Submeshes的模型只能合并无奈渲染显示进去。不带多个Submeshes的模型可能失常合并显示。 A:测试发现,须要对每个CombineInstance从新指定三角面,能力失常显示带多个Submeshes的模型。 如这段代码: foreach (SkinnedMeshRenderer smr in allSkineMeshList) { for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++) { CombineInstance ci = new CombineInstance(); ci.mesh = smr.sharedMesh; ci.mesh.triangles = smr.sharedMesh.triangles; //这里从新指定 ci.subMeshIndex = sub; ci.transform = matrix * smr.transform.localToWorldMatrix; combineInstances.Add(ci); } } 感激题主牛头人不服@UWA问答社区提供了答复 ...

March 17, 2021 · 1 min · jiezi

关于lua:luarockscn-中国首个-Lua-模块代理服务

LuaRocks 是应用最宽泛的 Lua 模块管理工具,与之绝对应的则是 https://luarocks.org,一个公共的 LuaRocks 服务。用户或通过 https://luarocks.org 下载其所需的 Lua 模块,或向 https://luarocks.org 上传本人开发的 Lua 模块。 然而该服务并没有设立中国站点,这意味着每当用户须要下载或者上传一个 Lua package 的时候,可能须要和位于远在太平洋彼端的服务器进行通信,延时之高可想而知,尤其对于像 Apache APISIX 这样蕴含泛滥 Lua 依赖模块的我的项目来说,拉取依赖所破费的工夫更是令人咋舌,这大大降低了应用 LuaRocks 的体验。 干流科技近日推出了 luarocks.cn 服务,该服务旨在减速国内用户拜访 https://luarocks.org 的速度。该服务面向所有开发者,且完全免费。只须要简略的配置即可应用该服务。例如,在下载某一个 Lua 模块的时候,在 --server 参数中指定 https://luarocks.cn 即可应用到该代理服务,如下两条命令通过 luarocks.cn 装置了 Apache APISIX 和 Kong。 $ luarocks install apisix --server https://luarocks.cn $ luarocks install kong --server https://luarocks.cn 此外,你能够通过批改 LuaRocks 的配置文件,如 ~/.luarocks/config.lua 和 ~/.luarocks/upload_config.lua (别离用于下载和上传),来无缝应用 luarocks.cn 服务。 # cat .luarocks/upload_config.lua rocks_servers = { "https://luarocks.cn"}# cat ~/.luarocks/upload_config.luakey = "<Your API Key>"server = "https://luarocks.cn"

March 8, 2021 · 1 min · jiezi

关于lua:从Lua中的字符串中提取数字

能够应用%D+删除string.gsub(1个或多个非数字字符)模式前面的所有匹配项: s = "($1,000)"res, _ = s:gsub("%D+", "")print(res)-- => 1000 请参阅Lua demo

March 5, 2021 · 1 min · jiezi

关于lua:Lua全局变量代码规范

1)Lua全局变量代码标准2)AssetBundle LockPersistentManager开销3)Unity内置字体在资源检测报告中不算冗余资源4)特定Android设施上,Adreno产生冻屏问题5)Mask和RectMask性能上的区别 这是第238篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) LuaQ:应用Lua语言作为脚本辅助开发曾经十分风行了,然而Lua语言中的全局变量是一个令人头疼的问题,因为无需申明就能够应用、编译器编译不会针对重命名和笼罩进行报错,稍不留神就会笼罩掉全局变量导致Bug,而且全局变量援用GameObject有可能会造成泄露。 大家在开发过程中,对于Lua全局变量会制订什么代码标准吗?例如:什么时候能够应用全局变量?如何申明?如何躲避笼罩等问题,谢谢。 A:能够在Lua虚拟机启动当前,在适当的机会执行一下luaGlobalCheck.lua文件,这个文件外面会设置一下_G的元表和元办法,通过重写_newindex和 _index元办法的形式来做到禁止新建全局变量和拜访不存在的全局变量时提醒谬误。这样能够做到防止随便新建全局变量污染环境和笼罩的问题。 luaGlobalCheck.lua代码如下: setmetatable(_G, { -- 管制新建全局变量 __newindex = function(_, k) error("attempt to add a new value to global,key: " .. k, 2) end, -- 管制拜访全局变量 __index = function(_, k) error("attempt to index a global value,key: "..k,2) end}) 感激马三小伙儿@UWA问答社区提供了答复 AssetBundleQ:察看性能曲线,发现某一帧AssetBundle加载中,LockPersistentManager耗时比拟大。请问这块是否可能优化? A1:这阐明以后帧或前几帧中存在较大量的资源在通过LoadAsync来进行加载,其本质是所加载的资源过大所致,对本身资源进行正当优化可升高Loading.LockPersistentManager的开销。另外,将异步加载换成同步加载,LockPersistentManager就不会呈现了,但其总加载耗时是没有变动的,因为总加载量没变。对于次要资源的加载优化,可参考如下链接:《Unity加载模块深度解析(纹理篇)》《Unity加载模块深度解析(网格篇)》《Unity加载模块深度解析(Shader篇)》《Unity加载模块深度解析之动画片段》《移动游戏加载性能和内存治理全解析》 该答复由UWA提供 A2:Unity 2019.4.1版本下,其实是bundle.LoadFromFileAsync在主线程的Integrate Asset中执行,和PreloadManager线程的LoadAssetAsync不能同时进行,必须要锁,也就呈现LockPersistentmanager,始终锁到一方完结。实质还是这块实现不欠缺,能够用Spin Lock始终锁到Application.backgroundLoadingPriority规定的工夫再到下一帧就行了,不必始终锁到一方开释。 Unity 2019.4.11和2019.4.16批改了主线程读Bundle和等锁的问题: 我在Unity 2020.1.17版本出的iOS上测试是根本解决了: 然而还有个别异步加载主线程等锁的景象,预计是资源太大收集依赖工夫太长触发的: 感激燃野@UWA问答社区提供了答复 AssetBundleQ:咱们的我的项目工程中返现两个界面的Prefab,都是用Unity本人的Arial字体生成的Bundle,上传到资源检测,然而在报告中并未看到内置的字体是冗余资源。 A1:这个Arial是属于Unity内置资源,打包APK的时候是会被打进unity default resources外面的,所以AssetBundle中应用到了这个Arial字体都是援用关系,并不会打包进对应的AssetBundle中,因而看不到冗余是失常的。应用AssetStudio关上APK包中的assets/bin/Data/目录下的unity default resources就能够看到了,如下图: ...

February 26, 2021 · 1 min · jiezi

关于lua:基于openresty的web-api框架

用openresty搭建的一个繁难web api框架,不便之后用的时候疾速生成我的项目构造 我的项目地址点击这里 目录构造构造供蕴含config、controller、libs、model四个目录 config 配置文件目录,用于app、redis、database相干的配置 app利用相干return { default_controller = 'home', -- 默认控制器 default_action = 'index', -- 默认办法}数据库相干local mysql_config = { timeout = 5000, connect_config = { host = "127.0.0.1", port = 3306, database = "demo", user = "root", password = "a12345", max_packet_size = 1024 * 1024 }, pool_config = { max_idle_timeout = 20000, -- 20s pool_size = 50 -- connection pool size }}redis配置return { host = "127.0.0.1", -- redis host port = 6379, -- the port max_idle_timeout = 60000, -- max idle time pool_size = 1000, -- pool size timeout = 1000, -- timeout time db_index= 2, -- database index }libs目录libs目录上面的公共的模块库,包含redis、db、request、response等 ...

January 1, 2021 · 2 min · jiezi

关于lua:lua和C语言互相调用的例子

之前都是看的lua脚本怎么写的,还有就是在之前的工作室仿照着写。没有真正懂LUA和C语言如何之间交互的。明天写了一个例子 首先我要实现的性能计算两个整数的和,就是x+y了。因为x和y是随时变动的,我又不想在C程序里批改,那么就把这两个参数放到lua脚本来传递。 那么我是如何实现的呢? 第一步:搭建window环境,应用vs2005 这个货色在网上搜寻一下吧,很多。 第二步:写一下c函数的逻辑。 //testlua.c#include "stdafx.h"#include <stdio.h>extern "C" {#include "lua.h"#include "lualib.h"#include "lauxlib.h"}lua_State* L;int add(lua_State* L);int add(lua_State* L){//从L栈中取出索引为1的数值,并查看int x = luaL_checkint(L,1);//从L栈中取出索引为2的数值,并查看int y = luaL_checkint(L,2);printf("result:%dn",x+y);return 1;}int _tmain(int argc, _TCHAR* argv[]){//初始化全局LL = luaL_newstate();//关上库luaL_openlibs(L);//把函数压入栈中lua_pushcfunction(L, add);//设置全局ADDlua_setglobal(L, "ADD");//加载咱们的lua脚本文件if (luaL_loadfile(L,"E:workvsProjecttestLuamylua.lua")){printf("errorn");}//安全检查lua_pcall(L,0,0,0);//push进lua函数lua_getglobal(L, "mylua");lua_pcall(L,0,0,0);printf("hello my luan");return 0;} x上面是我的lua脚本代码,很简略 function mylua()print("mylua")ADD(1,2)ADD(3,4)end ADD(1,2) 关联到注册到的add函数,把参数压入了。 最初输入后果为: 看是不是很简略啊

November 11, 2020 · 1 min · jiezi

关于lua:我们一起来学lua协程coroutine-四

明天咱们先来看下lua手册上一个协程实例: 手册实例:function foo(a) print("foo", a) return coroutine.yield(2 * a)endco = coroutine.create(function ( a, b ) print("co-body", a, b) local r = foo(a + 1) print("co-body", r) local r, s = coroutine.yield(a + b, a - b) print("co-body", r, s) return b, "end"end)print("main", coroutine.resume(co, 1, 10))print("main", coroutine.resume(co, "r"))print("main", coroutine.resume(co, "x", "y"))print("main", coroutine.resume(co, "x", "y"))执行后果:co-body 1 10 -- 协程co的第7行,此时resume()传入的参数是赋值给了函数的foo 2 -- 在第8行外面调用了函数foo(),执行到第2行的打印main true 4 -- 因为函数foo()的第3行yield()执行后挂起,参数是4,作为第15行的resume()的第二个返回值,最终打印了进去,到此,第15行执行结束co-body r -- 第16行resume()再次唤醒协程co,接着上次yield()的中央继续执行,参数“r"被赋值给上次yield()的返回值,在第9行打印进去main true 11 -9 -- 在第10行yiled()后再次挂起协程co,并返回,此时参数a和b还是第一次resume()时的参数,1,10,所以yield()两个参数别离为11,-9,作为resum()的第二个返回值,最终被打印进去,到此,第16行执行结束co-body x y -- 第17行resume()再次唤醒协程co,传入的参数“x”,“y”被赋值给上次的yield()函数的返回值,即赋值给第10行的r,s,在第11行被打印进去main true 10 end -- 协程co在第12行返回,留神此时参数b依然是第一次resume()时的参数2,值为10,至此协程co执行完结,变为dead状态,最终在第17行打印进去main false cannot resume dead coroutine -- 第18行尝试再次resume()协程co,因为协程co曾经为dead状态,所以间接返回并报错下面这个实例很好的展现了coroutine.yield和coroutine.resume之间的相互作用。协程在生产者和消费者问题上应该用也比拟宽泛,咱们来看看上面这个例子。 ...

September 23, 2020 · 1 min · jiezi

关于lua:我们一起来学lua协程coroutine-三

*上一期咱们次要介绍了协程的相干函数,以及协程的创立。这一期,咱们次要来介绍协程怎么进行合作的,而合作也正是协程的精髓所在,小伙伴们,小板凳带好了嘛?≧◠◡◠≦✌*生存当中咱们做事件常常都是不可能一干到底的。比方,你正在看书,这时候忽然来了个电话,或者说你在跟朋友家人视频聊天,这时候忽然没信号了了。在这种状况下,咱们都不得不停下原先手中的事件,去解决其余事件,等其余事件解决完了,再接着原先的事件往下走。为了解决这样的问题,协程也提供了合作机制。咱们先来看看上面的一个简略实例。合作实例一:--创立一个协程,但还没有调用read_co = coroutine.create( function () print("看书") print("有电话打进来") coroutine.yield() print("电话打完了,持续看书") end)--开启读书协程coroutine.resume(read_co)print("打电话")coroutine.resume(read_co)运行后果:看书有电话打进来打电话电话打完了,持续看书实例通过coroutine.yield()挂起协程,而后又通过coroutine.resume切换回协程,持续往下执行。是不是很简略?接下来咱们来看下coroutine.yield跟coroutine.resume更深一步的做法,咱们还是间接看实例吧。 协程实例二:--创立一个协程,但还没有调用read_co = coroutine.create( function () print("看书") print("有电话打进来") local ret1, ret2 = coroutine.yield("我读到第三章了", "第二章很精彩") print("ret1 = "..ret1) print("ret2 = "..ret2) print("电话打完了,持续看书") end)--开启读书协程local ret1, ret2, ret3 = coroutine.resume(read_co)print(ret1)print("ret2 = "..ret2)print("ret3 = "..ret3)print("打电话")coroutine.resume(read_co,"王老师打来的电话","让我读第五章")运行后果: 看书有电话打进来trueret2 = 我读到第三章了ret3 = 第二章很精彩打电话ret1 = 王老师打来的电话ret2 = 让我读第五章电话打完了,持续看书从这个实例咱们能够看到coroutine.yield的参数能够返回给前一个coroutine.resume。这里须要留神的是coroutine.resume的第一个返回值是协程运行是否出错,通过打印咱们能够晓得这里要么等于true要么等于false。从第二个返回值开始才是coroutine.yield传进去的值。协程应用coroutine.yield挂起之后,如何使它继续执行呢?还是要通过coroutine.resume,这时候coroutine.yield的返回值也就是coroutine.resume的入参信息。这里童鞋们看明确了?好了明天协程内容就介绍到这里,今天咱们持续深入探讨协程的合作问题,以及合作在异步通信的具体利用~~~

September 22, 2020 · 1 min · jiezi

关于lua:我们一起来学lua协程coroutine-二

大家好,骚气十足的额,又来了,对,明天咱们次要来学习下lua协程的用法,小伙伴们筹备好小板凳,筹备开车了~~~(ps:如同有点偏题了,不过不重要你们当作没看见就行(O ^ ~ ^ O)) 协程次要函数:函数名入参返回值形容coroutine.create()承受单个参数,这个参数是coroutine的主函数返回它的控制器,(一个对象为thread)的对象创立 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合应用的时候就唤醒函数调用coroutine.resume()第一个参数:coroutine.create的返回值,即一个thread对象。第二个参数:coroutine中执行须要的参数,是一个变长参数,可传任意多个参数。如果程序没有任何运行谬误的话,那么会返回true,之后的返回值是前一个调用coroutine.yleld中传入的参数。如果有任何谬误的话,就会返回false,加上错误信息重启 coroutine(重启时不必再传参数),和 create 配合应用coroutine.yield()传入变长参数,这些参数会作为返回值被 coroutine.resume接管返回在前一个调用coroutine.resume()中传入的参数值挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合应用能有很多有用的成果(返回参数)coroutine.running()空返回以后正在运行的协程。如果它被主线程调用的话,会返回nil返回正在跑的 coroutine,一个 coroutine 就是一个线程,当应用running的时候,就是返回一个 corouting 的线程号如果没有返回nilcoroutine.status()空返回以后协程的状态:有running,suspended,normal,dead返回正在跑的 coroutine,一个 coroutine 就是一个线程,当应用running的时候,就是返回一个 corouting 的线程号如果没有返回nil创立协程实例: --创立一个协程co = coroutine.create( function (str) print(str); end)print("以后协程状态:"..coroutine.status(co))运行后果: 以后协程状态:suspended创立协程的函数是coroutine.create,调用这个函数胜利之后就会返回一个协程对象,后续咱们无关协程的操作就围绕这个对象进行。下面的例子co就是咱们协程对象。通过coroutine.status这个函数查看协程状态,咱们能够发现以后的状态是suspended挂起状态,也就是说coroutine.create只实现创立协程的动作,然而协程当初并没有跑起来,不然这时候的状态就应该是running了。为了让协程跑起来,这时候就轮到coroutine.resume这个函数大展拳脚了。咱们再来看下上面这hello world例子。(ps:人人都爱hello world 不要厌弃博主举的例子很low啊≧◠◡◠≦✌) hello world例子: --创立一个协程,但还没有调用co = coroutine.create( function (str) print(str); end)--开启协程,打印hello world!coroutine.resume(co,"hello world!")通过hello world这个例子咱们就能够分明的看到协程失常运行起来了,这时候协程的状态是runnning嘛?有趣味的童鞋能够打印进去看看,想想看为什么是这个状态。有时候我感觉,学习编程,最重要的还是大家可能多入手,多思考。不然就算我博客写得再具体,大家可能把握的货色还是很无限的。just do it~~~话不多说,干就是了! lua中文手册参考文章一参考文章二

September 21, 2020 · 1 min · jiezi