在饥荒中,有一些东西是可以找到代码定义的:
EntityScript:DoTaskInTime()
定义在 scripts/entityscript.lua
KnownModIndex:GetModInfo()
定义在 scripts/modindex.lua
TheFrontEnd:PushScreen()
定义在 scripts/frontend.lua
但是也有一些东西只能找到使用它的地方,而找不到定义位置:
TheNet:IsDedicated()
TheSim:FindEntities()
WorldSim:SetWorldSize()
inst.AnimState:PlayAnimation()
如果更仔细一点研究,可以发现TheNet
, TheSim
, WorldSim
这些东西的类型不是table,而是userdata。
print(type(TheNet))
userdata
饥荒用的代码是c++和Lua,userdata其实就是写在了c++部分,所以看不见定义。
userdata不是表,不能直接用pairs和ipairs遍历。
for k,v in pairs(TheNet)do print(k,v) end
bad argument #1 to 'pairs' (table expected, got userdata)
你可以查看userdata的所有函数名字,注意这里使用了元表相关操作:
(不懂元表也没关系,知道代码怎么写就行)
for k,v in pairs(getmetatable(TheNet).__index)do print(k,v) end
GetDefaultMaxPlayers function: 0x6000005d88c0 SetIsMatchStarting function: 0x6000005da840 GetServerIsDedicated function: 0x6000005d9c00 PrintNetwork function: 0x6000005df680 SetDefaultMaxPlayers function: 0x6000005d8900 ViewNetFriends function: 0x6000005d9d40 SetDefaultGameMode function: 0x6000005d8540 GetClientMetricsForUser function: 0x6000005d9940 GetServerIsClientHosted function: 0x6000005d9c40 TruncateSnapshotsInClusterSlot function: 0x6000005d9640 SystemMessage function: 0x6000005df740 GetWorldSessionFile function: 0x6000005d9180 SendRPCToClient function: 0x6000005deec0 ...(还有一大堆)
虽然能看到函数名字,但是看不了源代码定义,具体用法需要结合函数名和官方使用案例去理解。
你可以修改现有的userdata里面的函数,也可以定义一个自己的函数。
函数的第一个参数是userdata自身。
写一个新的函数,叫TheNet:PrintStatus()
。
getmetatable(TheNet).__index.PrintStatus = function(net) print("Is Server:", net:GetIsServer()) print("Is Client:", net:GetIsClient()) print("Is Dedicated", net:IsDedicated()) end TheNet:PrintStatus()
因为我是在游戏主界面运行的,所以结果都是false。
Is Server: false Is Client: false Is Dedicated false
让TheSim:FindEntities()
函数每次被调用的时候,都打印搜索到的实体数量。
local mt = getmetatable(TheSim).__index local old_FindEntities = mt.FindEntites mt.FindEntities = function(sim, ...) local ents = old_FindEntities(sim, ...) print("查找到"..#ents.."个实体!") return ents end
如果要修改AnimState, Physics, Transform 之类的函数,常规操作是获取元表修改:
local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() local mt = getmetatable(inst.AnimState).__index function mt.PlayAndPush(anim, name1, name2) anim:PlayAnimation(name1) anim:PushAnimation(name2) end
但其实klei已经把这个表放到全局变量里了,你可以直接修改:
function AnimState.PlayAndPush(anim, name1, name2) anim:PlayAnimation(name1) anim:PushAnimation(name2) end
然后就能在其他地方用这个新增的PlayAndPush
函数了:
local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.AnimState:SetBank("wilson") inst.AnimState:SetBuild("wilson") inst.AnimState:PlayAndPush("run_start", "run_loop") ---<
上述操作都可以在klei源代码里看到。
scripts/debugsounds.lua
scripts/postprocesseffects.lua
(联机)