当前位置: 首页 > news >正文

xyz域名做网站好么学生做兼职哪个网站

xyz域名做网站好么,学生做兼职哪个网站,wordpress woocommerce,wordpress js加载慢最近沉迷lua脚本热更#xff0c;想说这个可以提高多少菜鸡的调试效率#xff0c;找了网上好多文章#xff0c;但是都不行#xff0c;尝试了很久#xff0c;并且自己测试和学习#xff0c;写了一遍#xff0c;勉强能热更了。下面记录一下热更Lua的过程。一、用来卸载表格… 最近沉迷lua脚本热更想说这个可以提高多少菜鸡的调试效率找了网上好多文章但是都不行尝试了很久并且自己测试和学习写了一遍勉强能热更了。下面记录一下热更Lua的过程。一、用来卸载表格的加载最简单粗暴的热更新就是将package.loaded[modelname]的值置为nil强制重新加载function reload_module_obsolete(module_name) package.loaded[module_name] nil require(module_name)end这样做虽然能完成热更但问题是已经引用了该模块的地方不会得到更新 因此我们需要将引用该模块的地方的值也做对应的更新。function ReloadUtil.Reload_Module(module_name)local old_module _G[module_name] package.loaded[module_name] nil require (module_name)local new_module _G[module_name]for k, v in pairs(new_module) do old_module[k] vend package.loaded[module_name] old_moduleend二、我认为逻辑最清晰的但是可能是我不会用吧源链接链接--region 利用_ENV环境在加载的时候把数据加载到_ENV下然后再通过对比的方式修改_G底下的值从而实现热更新函数 -- 失败function ReloadUtil.hotfix(chunk, check_name) check_name check_name or hotfixlocal env {} setmetatable(env, { __index _G })local f, err load(chunk, check_name, t, env) assert(f,err)local ok, err pcall(f) assert(ok,err)local protection { setmetatable true, pairs true, ipairs true, next true, require true, _ENV true, }--防止重复的table替换造成死循环local visited_sig {}function ReloadUtil.update_table(newTable, oldTable, name, deep)--对某些关键函数不进行比对if protection[newTable] or protection[oldTable] then return end--如果原值与当前值内存一致值一样不进行对比if newTable oldTable then return endlocal signature tostring(oldTable)..tostring(newTable)if visited_sig[signature] then return end visited_sig[signature] true--遍历对比值如进行遍历env类似的步骤for name, newValue in pairs(newTable) dolocal old_value oldTable[name]if type(newValue) type(old_value) thenif type(newValue) function then ReloadUtil.update_func(newValue, old_value, name, deep.. ..name.. ) oldTable[name] newValueelseif type(newValue) table then ReloadUtil.update_table(newValue, old_value, name, deep.. ..name.. )endelse oldTable[name] newValueendend--遍历table的元表进行对比local old_meta debug.getmetatable(oldTable)local new_meta debug.getmetatable(newTable)if type(old_meta) table and type(new_meta) table then ReloadUtil.update_table(new_meta, old_meta, name..s Meta, deep.. ..name..s Meta.. )endendfunction ReloadUtil.update_func(newFunc, oldFunc, name, deep)--取得原值所有的upvalue保存起来local old_upvalue_map {}for i 1, math.huge dolocal name, value debug.getupvalue(oldFunc, i)if not name then break end old_upvalue_map[name] valueend--遍历所有新的upvalue根据名字和原值对比如果原值不存在则进行跳过如果为其它值则进行遍历env类似的步骤for i 1, math.huge dolocal name, value debug.getupvalue(newFunc, i)if not name then break endlocal old_value old_upvalue_map[name]if old_value thenif type(old_value) ~ type(value) then debug.setupvalue(newFunc, i, old_value)elseif type(old_value) function then ReloadUtil.update_func(value, old_value, name, deep.. ..name.. )elseif type(old_value) table then ReloadUtil.update_table(value, old_value, name, deep.. ..name.. ) debug.setupvalue(newFunc, i, old_value)else debug.setupvalue(newFunc, i, old_value)endendendend--原理--利用_ENV环境在加载的时候把数据加载到_ENV下然后再通过对比的方式修改_G底下的值从而实现热更新函数for name,value in pairs(env) dolocal g_value _G[name]if type(g_value) ~ type(value) then _G[name] valueelseif type(value) function then ReloadUtil.update_func(value, g_value, name, G.. ) _G[name] valueelseif type(value) table then ReloadUtil.update_table(value, g_value, name, G.. )endendreturn 0endfunction ReloadUtil.hotfix_file(debugName)local newCodelocal fp io.open(debugName)if fp then newCode fp:read(*all) io.close(fp)endif not newCode thenreturn -1endreturn ReloadUtil.hotfix(newCode, debugName)end--endregion图文无关三、有点复杂递归了debug.getregistry()然后去替换旧的值源链接asqbtcupid.github.io/lu 有介绍原理讲得还蛮细的学习了蛮多但是这个递归真的是复杂我注释掉了一些递归能满足基本的需求。local ReloadUtil {}local tableInsert table.insertlocal tableRemove table.removelocal tableConcat table.concatlocal ioPopen io.popenlocal ioInput io.inputlocal ioRead io.readlocal stringMatch string.matchlocal stringFind string.findlocal stringSub string.sublocal stringGsub string.gsublocal packageLoaded package.loadedlocal type typelocal getfenv getfenvlocal setfenv setfenvlocal loadstring loadstringlocal mathHuge math.hugelocal debugGetupvalue debug.getupvaluelocal debugSetupvalue debug.setupvaluelocal debugGetmetatable debug.getmetatablelocal debugSetfenv debug.setfenvfunction ReloadUtil.FailNotify(...) printAError(...)endfunction ReloadUtil.DebugNofity(...) print(...)endfunction ReloadUtil.ErrorHandle(e) ReloadUtil.FailNotify(HotUpdate Error\n..tostring(e)) ReloadUtil.ErrorHappen trueendfunction ReloadUtil.InitProtection() ReloadUtil.Protection {}local Protection ReloadUtil.Protection Protection[setmetatable] true Protection[pairs] true Protection[ipairs] true Protection[next] true Protection[require] true Protection[ReloadUtil] true Protection[ReloadUtil.Meta] true Protection[math] true Protection[string] true Protection[table] trueendlocal function Normalize(path) path path:gsub(/,\\)local pathLen #pathif path:sub(pathLen, pathLen) \\ then path path:sub(1, pathLen - 1)endlocal parts { }for w in path:gmatch([^\\]) doif w .. and #parts ~0 then tableRemove(parts)elseif w ~ . then tableInsert(parts, w)endendreturn tableConcat(parts, \\)end-- 根据给的路径找到路径下所有文件HU.FileMap[FileName] {SysPath line, LuaPath luapath}function ReloadUtil.InitFileMap(RootPath)local systemPathList {}local HotUpdateDic ReloadUtil.HotUpdateDiclocal OldCode ReloadUtil.OldCode RootPath Normalize(RootPath)--获取一个File对象其下的所有文件和目录的绝对路径: 的所有文件(/S/B)不包括文件夹(/A:A)ioPopen返回文件句柄file handle--todo 这里有的问题多次启动后会报bad file decorator 检查是否是打开文件没有关闭导致local file ioPopen(dir /S/B /A:A \..RootPath..\)for SysPath in ioInput(file):lines() dolocal FileName stringMatch(SysPath,.*\\(.*)%.lua)--todo meta 优化一下regexlocal metaFile stringMatch(SysPath,.*\\(.*)%.lua.meta)if FileName ~ nil and metaFile nil then--todo !!! luaPath在保存的时候是按文件夹路径保存的比如game.modules.XXX.lua所以可能要自己搞对这个路径local startIndex stringFind(SysPath,game)local luaPath stringSub(SysPath, startIndex, #SysPath -4) luaPath stringGsub(luaPath, \\, .) HotUpdateDic[luaPath] SysPath tableInsert(systemPathList,SysPath)-- 初始化旧代码 ioInput(SysPath) OldCode[SysPath] ioRead(*all) ioInput():close()endend file:close()return systemPathListendfunction ReloadUtil.InitFakeTable()local meta {} ReloadUtil.Meta metalocal function FakeT() return setmetatable({}, meta) endlocal function EmptyFunc() endlocal function pairs() return EmptyFunc endlocal function setmetatable(t, metaT) ReloadUtil.MetaMap[t] metaTreturn tendlocal function getmetatable(t, metaT)return setmetatable({}, t)endlocal function require(LuaPath)if not ReloadUtil.RequireMap[LuaPath] thenlocal FakeTable FakeT() ReloadUtil.RequireMap[LuaPath] FakeTableendreturn ReloadUtil.RequireMap[LuaPath]endfunction meta.__index(table, key)if key setmetatable thenreturn setmetatableelseif key pairs or key ipairs thenreturn pairselseif key next thenreturn EmptyFuncelseif key require thenreturn requireelselocal FakeTable FakeT() rawset(table, key, FakeTable)return FakeTableendendfunction meta.__newindex(table, key, value) rawset(table, key, value) endfunction meta.__call() return FakeT(), FakeT(), FakeT() endfunction meta.__add() return meta.__call() endfunction meta.__sub() return meta.__call() endfunction meta.__mul() return meta.__call() endfunction meta.__div() return meta.__call() endfunction meta.__mod() return meta.__call() endfunction meta.__pow() return meta.__call() endfunction meta.__unm() return meta.__call() endfunction meta.__concat() return meta.__call() endfunction meta.__eq() return meta.__call() endfunction meta.__lt() return meta.__call() endfunction meta.__le() return meta.__call() endfunction meta.__len() return meta.__call() endreturn FakeTendfunction ReloadUtil.IsNewCode(SysPath) ioInput(SysPath)local newCode ioRead(*all)local oldCode ReloadUtil.OldCode[SysPath]if oldCode newCode then ioInput():close()return falseend ReloadUtil.DebugNofity(SysPath)return true, newCodeendfunction ReloadUtil.GetNewObject(newCode, LuaPath, SysPath)--loadstring 一段lua代码以后会经过语法解析返回一个函数执行返回的函数时字符串中的代码就被执行了。local NewFunction loadstring(newCode)if not NewFunction then ReloadUtil.FailNotify(SysPath.. has syntax error.) collectgarbage(collect)else-- 把加载的字符串放置在空环境了防止报错 setfenv(NewFunction, ReloadUtil.FakeENV)local NewObject ReloadUtil.ErrorHappen false--类似其它语言里的 try-catch, xpcall 类似 pcall xpcall接受两个参数调用函数、错误处理函数-- todo 父类没拿到 xpcall(function () NewObject NewFunction() end, ReloadUtil.ErrorHandle)if not ReloadUtil.ErrorHappen then ReloadUtil.OldCode[SysPath] newCodereturn NewObjectelse collectgarbage(collect)endendendfunction ReloadUtil.ResetENV(object, name, From, Deepth)local visited {}local function f(object, name)if not object or visited[object] then return end visited[object] trueif type(object) function then ReloadUtil.DebugNofity(Deepth..HU.ResetENV, name, from:..From) xpcall(function () setfenv(object, ReloadUtil.ENV) end, ReloadUtil.FailNotify)elseif type(object) table then ReloadUtil.DebugNofity(Deepth..HU.ResetENV, name, from:..From)for k, v in pairs(object) do f(k, tostring(k)..__key, HU.ResetENV , Deepth.. ) f(v, tostring(k), HU.ResetENV , Deepth.. )endendend f(object, name)end-- 遍历_G这张全局表替换HU.ChangedFuncList 有改动列表 的函数function ReloadUtil.Travel_G()local visited {}local ChangedFuncList ReloadUtil.ChangedFuncList visited[ReloadUtil] truelocal function f(table)if (type(table) ~ function and type(table) ~ table) or visited[table] or ReloadUtil.Protection[table] then return end visited[table] trueif type(table) function thenfor i 1, mathHuge dolocal name, value debugGetupvalue(table, i)if not name then break endif type(value) function thenfor _, funcs in ipairs(ChangedFuncList) doif value funcs.OldObject then debugSetupvalue(table, i, funcs.NewObject)endendend-- todo--f(value)endelseif type(table) table then-- 不要漏掉元表和upvalue的表元表的获取用debug.getmetatable-- todo 这样对于有metatable这个key的元表也能正确获取。--f(debugGetmetatable(table))local changeIndexList {}for key, value in pairs(table) do-- todo 还有注意table的key也可以是函数。--f(key) f(value)if type(value) function thenfor _, funcs in ipairs(ChangedFuncList) doif value funcs.OldObject then table[key] funcs.NewObjectendendend-- 找出改动的indexif type(key) function thenfor index, funcs in ipairs(ChangedFuncList) doif key funcs.OldObject then changeIndexList[#changeIndexList 1] indexendendendend-- 修改改动的值for _, index in ipairs(changeIndexList) dolocal funcs ChangedFuncList[index] table[funcs.NewObject] table[funcs.OldObject] table[funcs.OldObject] nilendendend--遍历_G这张全局表_G在registryTable里--f(_G)--如果有宿主语言那么还要遍历一下注册表用debug.getregistry()获得。local registryTable debug.getregistry() f(registryTable)endfunction ReloadUtil.UpdateTable(OldTable, NewTable, Name, From, Deepth)if ReloadUtil.Protection[OldTable] or ReloadUtil.Protection[NewTable] then return endif OldTable NewTable then return endlocal signature tostring(OldTable)..tostring(NewTable)if ReloadUtil.VisitedSig[signature] then return end ReloadUtil.VisitedSig[signature] true ReloadUtil.DebugNofity(Deepth..HU.UpdateTable ..Name.. from:..From)for ElementName, newValue in pairs(NewTable) dolocal OldElement OldTable[ElementName]if type(newValue) type(OldElement) thenif type(newValue) function then ReloadUtil.UpdateOneFunction(OldElement, newValue, ElementName, OldTable, HU.UpdateTable, Deepth.. )elseif type(newValue) table then ReloadUtil.UpdateTable(OldElement, newValue, ElementName, HU.UpdateTable, Deepth.. )endelseif OldElement nil and type(newValue) function then-- 新增的函数添加到旧环境里if pcall(setfenv, newValue, ReloadUtil.ENV) then OldTable[ElementName] newValueendendend-- todo 更新metatable--local OldMeta debug.getmetatable(OldTable)--local NewMeta ReloadUtil.MetaMap[NewTable]--if type(OldMeta) table and type(NewMeta) table then-- ReloadUtil.UpdateTable(OldMeta, NewMeta, Name..s Meta, HU.UpdateTable, Deepth.. )--endend-- Upvalue 是指那些函数外被引用到的local变量function ReloadUtil.UpdateUpvalue(OldFunction, NewFunction, Name, From, Deepth) ReloadUtil.DebugNofity(Deepth..HU.UpdateUpvalue, Name, from:..From)local OldUpvalueMap {}local OldExistName {}-- 记录旧的upvalue表for i 1, mathHuge dolocal name, value debugGetupvalue(OldFunction, i)if not name then break end OldUpvalueMap[name] value OldExistName[name] trueend-- 新的upvalue表进行替换for i 1, mathHuge dolocal name, value debugGetupvalue(NewFunction, i)if not name then break endif OldExistName[name] thenlocal OldValue OldUpvalueMap[name]if type(OldValue) ~ type(value) then-- 新的upvalue类型不一致时用旧的upvalue debugSetupvalue(NewFunction, i, OldValue)elseif type(OldValue) function then-- 替换单个函数 ReloadUtil.UpdateOneFunction(OldValue, value, name, nil, HU.UpdateUpvalue, Deepth.. )elseif type(OldValue) table then-- 对table里面的函数继续递归替换 ReloadUtil.UpdateTable(OldValue, value, name, HU.UpdateUpvalue, Deepth.. ) debugSetupvalue(NewFunction, i, OldValue)else-- 其他类型数据有改变也要用旧的 debugSetupvalue(NewFunction, i, OldValue)endelse-- 对新添加的upvalue设置正确的环境表 ReloadUtil.ResetENV(value, name, HU.UpdateUpvalue, Deepth.. )endendendfunction ReloadUtil.UpdateOneFunction(OldObject, NewObject, FuncName, OldTable, From, Deepth)if ReloadUtil.Protection[OldObject] or ReloadUtil.Protection[NewObject] then return endif OldObject NewObject then return endlocal signature tostring(OldObject)..tostring(NewObject)if ReloadUtil.VisitedSig[signature] then return end ReloadUtil.DebugNofity(Deepth..HU.UpdateOneFunction ..FuncName.. from:..From) ReloadUtil.VisitedSig[signature] true--最后注意把热更新的函数的环境表再改回旧函数的环境表即可方法是setfenv(newfunction, getfenv(oldfunction))。if pcall(debugSetfenv, NewObject, getfenv(OldObject)) then ReloadUtil.UpdateUpvalue(OldObject, NewObject, FuncName, HU.UpdateOneFunction, Deepth.. ) ReloadUtil.ChangedFuncList[#ReloadUtil.ChangedFuncList 1] {OldObject OldObject,NewObject NewObject,FuncName FuncName,OldTable OldTable}endendfunction ReloadUtil.ReplaceOld(OldObject, NewObject, LuaPath, From)if type(OldObject) type(NewObject) thenif type(NewObject) table then ReloadUtil.UpdateTable(OldObject, NewObject, LuaPath, From, )elseif type(NewObject) function then ReloadUtil.UpdateOneFunction(OldObject, NewObject, LuaPath, nil, From, )endendendfunction ReloadUtil.HotUpdateCode(LuaPath, SysPath)local OldObject packageLoaded[LuaPath]if not OldObject then-- 没加载的就不热更returnendlocal isNew,newCode ReloadUtil.IsNewCode(SysPath)if not isNew thenreturnendlocal newObject ReloadUtil.GetNewObject(newCode,SysPath,LuaPath)-- 更新旧代码 ReloadUtil.ReplaceOld(OldObject, newObject, LuaPath, Main)--原理--利用_ENV环境在加载的时候把数据加载到_ENV下然后再通过对比的方式修改_G底下的值从而实现热更新函数--setmetatable(ReloadUtil.FakeENV, nil)--todo --ReloadUtil.UpdateTable(ReloadUtil.ENV, ReloadUtil.FakeENV, ENV , Main, )-- 替换完上一次的代码就是旧代码 ReloadUtil.OldCode[SysPath] newCodeend-- 外部调用(先Init需要的路径然后Update是热更时候调用的)---param RootPath 需要被更新的文件夹路径---param UpdateListFile 需要被更新的文件列表,不传为整个文件夹会卡function ReloadUtil.Init(RootPath, ENV) ReloadUtil.HotUpdateDic {} ReloadUtil.FileMap {} ReloadUtil.OldCode {} ReloadUtil.ChangedFuncList {} ReloadUtil.VisitedSig {} ReloadUtil.FakeENV ReloadUtil.InitFakeTable()()--当我们加载lua模块的时候这时候这个模块信息并不像初始化全局代码一样就算提前设置了package.loaded[AA] nil,--也不会出现在env中同时也不会调用_G的__newindex函数也就是说env[AA]为空故这种写法无法进行热更新所以通常模块的写法改成如下--定义模块AAlocal AA {}--相当于package.seeall setmetatable(AA, {__index _G})--环境隔离local _ENV AA ReloadUtil.NewENV _ENV ReloadUtil.ENV ENV or _G ReloadUtil.InitProtection() ReloadUtil.ALL falsereturn ReloadUtil.InitFileMap(RootPath)endfunction ReloadUtil.Update() ReloadUtil.VisitedSig {} ReloadUtil.ChangedFuncList {}for LuaPath, SysPath in pairs(ReloadUtil.HotUpdateDic) do ReloadUtil.HotUpdateCode(LuaPath, SysPath)endif #ReloadUtil.ChangedFuncList 0 then ReloadUtil.Travel_G()end collectgarbage(collect)end我跟老大炫耀的时候老大说那你懂其中的原理吗一下问懵我了老大说你要学习到其中的原理才能进步啊不然就只是个会用工具的人。好有道理搞得我羞愧难当赶紧好好学习其中原理。UpvalueUpvalue 是指那些函数外被引用到的local变量,比如local a 1function foo() print(a)end那么a就是这个foo的upvalue。getupvalue (f, up)此函数返回函数 f 的第 up 个上值的名字和值。如果该函数没有那个上值返回 nil 。以 ( (开括号)打头的变量名表示没有名字的变量 (去除了调试信息的代码块)。setupvalue (f, up, value):这个函数将 value 设为函数 f 的第 up 个上值。如果函数没有那个上值返回 nil 否则返回该上值的名字。_G和debug.getregistry这2张表学习的时候我一直以为只有把_G这张全局表的旧值替换掉就好了然后真正实施的时候还是会有种种问题实在是很糟糕看这段代码的时候一直不是很理解看了debug.getregistry的定义debug.getregistry()返回注册表表这是一个预定义出来的表 可以用来保存任何 C 代码想保存的 Lua 值。还是半桶水但是我有注意到_G这种表其实在debug.getregistry返回的这张注册表里有所以最后就递归这张表其替换里面的旧值就好了。getfenv(object)返回对象的环境变量。setfenv(function,_ENV)设置一段代码的运行环境io.popen(dir /S/B /A:A \..RootPath..\)获取一个File对象其下的所有文件和目录的绝对路径: 的所有文件(/S/B)不包括文件夹(/A:A)io.popen返回文件句柄file handle对了InitFileMap这个函数有个要注意的luaPath在保存的时候是按文件夹路径保存的比如game.modules.XXX.lua所以可能要自己搞对这个路径最后总结一下流程1. 初始化需要热更的文件路径用一张哈希表存下来2. 然后遍历这些路径读取所有的代码判断是否是新代码新的话记录到ChangedFuncList列表里面3. 新代码的话就把加载的字符串放置在空环境了防止报错setfenv(NewFunction, ReloadUtil.FakeENV)4. 代替旧代码拿着ChangedFuncList列表到注册表(debug.getregistry())里面去找旧值递归注册表的旧值替换成新的值。来源知乎专栏Unity手游开发叨叨
http://www.zqtcl.cn/news/799514/

相关文章:

  • 微山县建设局官方网站wordpress 内容换行
  • 网站选择空间ps个人主页设计
  • 河北网站seo外包网站嵌入百度地图
  • 公司怎么开网站WordPress有哪些工具
  • 一流专业建设网站原平新闻头条最新消息
  • 网站开发文档模板 开源北京保障房建设项目网站
  • 营销型网站分类网站关键词如何快速上首页
  • 帝国和WordPress比较wordpress文章页标题优化
  • 宁晋网站建设温岭新站seo
  • 大学科研项目做网站成都免费建站模板
  • 兰州网站开发企业在微信公众号发布wordpress
  • 网站信息化建设总体情况网站建设介绍ppt模板下载
  • 广州 建网站asp.net.网站开发
  • 装修网站模板国家正规现货交易平台
  • 福州高端网站制作网站建设项目单子来源
  • 网站制作的行业广州网站推广方案
  • 网站主域名建设通怎么样
  • 网站是如何建立的广告设计与制作工作内容
  • 网站优化课程培训公司取名生成器免费
  • 如何设立网站做外国网站买域名
  • 惠州网站建设公司排名聊城专业网站设计公司
  • 网站建设龙岗电子商务有限公司官网
  • 分栏型网站服装设计网站模板
  • 建设网站备案与不备案区别企业网站怎么做排名
  • php mysql的网站开发html网站制作答辩ppt
  • 网站制作有名 乐云践新专家网页制作公司需要什么资质
  • 织梦怎么用框架实现在浏览器的地址栏只显示网站的域名而不显示出文件名电脑网站模板
  • 北京网络营销网站品牌营销增长公司哪家好
  • 网站反链有好处吗稷山网站建设
  • 廊坊网站群发关键词怎么在百度上推广自己的公司信息