今天又遇到了一个全新的问题,就是把昨天的鱼塘mod配方改了,然后可以做出来鱼塘了,但是这个鱼塘他并不会生产东西了。于是我今天继续琢磨起来了(x

在每个prefabs的看着很像构造方法的fn内一般能看到许多的inst:AddComponent操作,似乎是给这个实例绑定一个部件,嗯。。也有一种接口的意思,比如这段代码

1
2
3
inst:AddComponent("harvestable")
inst.components.harvestable:SetUp("pondfish", 3, nil, onharvest, updatelevel)
inst:ListenForEvent("childgoinghome", onchildgoinghome)

就是给当前实例绑定一个harvestable接口,让这个实例变成一个可被收获的实例,然后第二行进一步设置收获的规则,这里调用了一个harvestable实例的SetUp的函数,这个类的代码在scripts/components/harvestable.lua,代码如下

1
2
3
4
5
6
7
function Harvestable:SetUp(product, max, time, onharvest, ongrow)
self:SetProduct(product, max)
self:SetGrowTime(time)
self:SetOnGrowFn(ongrow)
self:SetOnHarvestFn(onharvest)
self:StartGrowing()
end

各个参数的语义也很清晰,然后看看这个接口是怎么实现的。在开头部分可以看到一部分类的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
local Harvestable = Class(function(self, inst)
self.inst = inst
self.produce = 0
self.growtime = nil
self.product = nil
self.ongrowfn = nil
self.maxproduce = 1
end,
nil,
{
produce = onproduce,
}
)

不得不说,lua这个闭包是真的很丑,虽然我也不清楚这个能不能算得上是一种闭包,但是从代码大概可以知道这个类会有哪些属性,好的我们继续。回到Harvestable:SetUp方法,可以看到方法体内部有5行。前面四行都是设置一些类属性的,然后最后调用了一个没有参数的方法,好的 那个很可疑,遂找到方法体:

1
2
3
4
5
6
7
8
function Harvestable:StartGrowing(time)
self:StopGrowing()
local growtime = time or self.growtime
if growtime then
self.task = self.inst:DoTaskInTime(growtime, function() self:Grow() end, "grow")
self.targettime = GetTime() + growtime
end
end

大意是,如果growtime有值的话就执行一个inst:DoTaskInTime,那么问题来了,这个代码好像不好找。

好了我又回来了,通过全局搜索DoTaskInTime(time找到了一个疑似该方法的定义,位于scripts/entityscript.lua文件内,代码如下:

1
2
3
4
5
6
7
8
9
10
11
function EntityScript:DoTaskInTime(time, fn, ...)
--print ("DO TASK IN TIME", time, self)
if not self.pendingtasks then
self.pendingtasks = {}
end

local per = scheduler:ExecuteInTime(time, fn, self.GUID, self, ...)
self.pendingtasks[per] = true
per.onfinish = task_finish -- function() if self and self.pendingtasks then self.pendingtasks[per] = nil end end
return per
end

对不起,看着有点复杂,涉及的可能会有点多,所以我决定先掠过一下,留下一个猜测根据scheduler:ExecuteInTime这是一个让某个函数在某个时间点后执行的方法。

然后在StartGrowing(time)内传入的是一个function() self:Grow() end的很像闭包的东西,好的然后找到中间那个方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Harvestable:Grow()
if self.produce < self.maxproduce then
self.produce = self.produce + 1
if self.ongrowfn then
self.ongrowfn(self.inst, self.produce)
end
if self.produce < self.maxproduce then
self:StartGrowing()
else
self:StopGrowing()
end
end
end

是一个非常简单的逻辑,所以对于这个接口是怎么运行的就大概明白了。

在前面的inst.components.harvestable:SetUp("pondfish", 3, nil, onharvest, updatelevel)内第三个时间参数是nil所以不会长,但是之前没改mod文件之前有蜜蜂会去采蜜,然后就会有鱼了。

但是在harvest部分还有第三行inst:ListenForEvent("childgoinghome", onchildgoinghome),意思似乎是添加一个Listener来监听孩子回家,然后第二个参数好像在哪里见过的方法,遂在这个mod的代码内搜索:

1
2
3
4
5
6
7
local function onchildgoinghome(inst, data)
if data.child and data.child.components.pollinator and data.child.components.pollinator:HasCollectedEnough() then
if inst.components.harvestable then
inst.components.harvestable:Grow()
end
end
end

哦豁,他直接在这里调用了harvestableGrow方法。所以意思是只要蜜蜂去采蜜了,那么就能有东西生成了,但是现在的问题是它根本就不产生蜜蜂。

所以猜测问题有可能是在生蜜蜂那里

1
2
3
4
5
6
7
8
9
inst:AddComponent("childspawner")
inst.components.childspawner.childname = "bee"
inst.components.childspawner:SetRegenPeriod(TUNING.BEEBOX_REGEN_TIME)
inst.components.childspawner:SetSpawnPeriod(TUNING.BEEBOX_RELEASE_TIME)
inst.components.childspawner:SetMaxChildren(TUNING.BEEBOX_BEES)

if TheWorld.state.isday and TheWorld.state.issummer then
inst.components.childspawner:StartSpawning()
end

嗯。。?这里怎么混进了一个判断语句?看语义是如果是在夏天的白天就开始生动物

感觉应该还有别的地方有这个StartSpawning,不然在其它季节建造的不就炸了。然后搜索StartSpawning,找到了这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local function OnIsDay(inst, isday)
if not isday then
if inst.components.harvestable and inst.components.harvestable.growtime then
inst.components.harvestable:StopGrowing()
end
if inst.components.childspawner then
inst.components.childspawner:StopSpawning()
end
elseif not TheWorld.state.iswinter then
if inst.components.harvestable and inst.components.harvestable.growtime then
inst.components.harvestable:StartGrowing()
end
if inst.components.childspawner then
inst.components.childspawner:StartSpawning()
end
end
end

逻辑有些混乱,找找在哪里调用了这个方法吧

1
inst:WatchWorldState("isday", OnIsDay)

感觉又是一个Listener,或者说Watcher?那么大概就明白了? 每个白天的开始都会执行一次这个方法?

然后在这个方法里面控制了怎么产生产物。

除此之外也有onsleepstopsleep的方法在里面控制了通过harvestable产生产品,并且在构造方法内把这两个方法绑定到了entitysleepentitywake两个Listener上,然而这两个Listener什么时候触发我也完全不知道。

剩下的东西明天再写,咕咕咕