1. 适用范围
本文只处理两个问题:
- 生长点刷新时间不准
补充时间随机增量 配了但实际不生效
本次最终修复只涉及 2 个文件:
/ubuntu/Game2/lualib/typegrowpointmanager.lua
/ubuntu/Game2/lualib/growpointenginer.lua
2. 问题现象
常见表现如下:
- 明明配置了
种子补充的间隔时间,实际刷新节奏忽快忽慢,或者明显比配置更快
- 配置了
补充时间随机增量,但现场表现始终像固定间隔
- 生长点达到上限后恢复补刷,重新计时不稳定
3. 老 C++ 的真实语义
通过 IDA 对老 Server 分析,生长点时间逻辑的关键语义是:
- 读取配置时保存两个基础字段:
OrgInterval
OrgIntervalInc
- 初始化当前间隔:
IntervalPerSeed = OrgInterval + OrgIntervalInc * (rand() % 100) / 100;
- 每次
HeartBeat 真正触发一轮补刷后,再重新计算下一轮间隔:
IntervalPerSeed = OrgInterval + OrgIntervalInc * (rand() % 100) / 100;
- 刷新触发条件是:
CurrentElapse > IntervalPerSeed
也就是说:
- 随机增量不是只在加载时算一次,而是每轮补刷后都要重新算下一轮
- 判定符号是
>,不是 >=
- 计时必须严格按真实 delta 累加,不能重复累计旧时间差
4. 配置字段对应关系
生长点配置表里和本文相关的字段是:
类型 数量 每次生成数量 生成函数 种子补充的间隔时间 补充时间随机增量
例如:
613 20 20 1800000 1200000
这条配置的含义是:
- 基础刷新间隔
1800000 ms
- 每轮额外随机增加
0 ~ 1188000 ms
- 每次真正完成一轮补刷后,要重新随机下一次间隔
Lua 最终实现用的是:
org + math.floor(inc * (math.random(100) - 1) / 100)
它和老 C++ 的:
org + inc * (rand() % 100) / 100
语义一致,随机范围都是 0 ~ 99%。
5. 第一处修改:修复刷新计时
文件:
/ubuntu/Game2/lualib/typegrowpointmanager.lua
最终代码:
function typegrowpointmanager:do_ticks()
if not self.enable then
return false
end
local utime = skynet.time() * 1000
if self.current_count >= self.max_appera_count then
self.start_count = false
self.current_elapse = 0
self.last_update_time = utime
return false
end
if not self.start_count then
self.start_count = true
self.last_update_time = utime
self.current_elapse = 0
return false
end
self.current_elapse = self.current_elapse + utime - self.last_update_time
self.last_update_time = utime
if self.current_elapse > self.interval_per_seed then
self.current_elapse = 0
return true
end
return false
end
这一版修复了 4 个关键点:
- 满额时停止计时,并重置
start_count/current_elapse
- 从“满额”回到“可补刷”时,重新起一轮完整计时
- 每次累计后都立即更新
last_update_time
- 触发条件使用
>,与老 C++ 保持一致
如果缺少这一句:
self.last_update_time = utime
后面的每次 heart_beat 都会反复累计“当前时间 - 老时间”,最终导致刷新时间越来越失真。
6. 第二处修改:加载基础间隔和随机增量
文件:
/ubuntu/Game2/lualib/growpointenginer.lua
在 load() 里初始化每个类型时,最终代码如下:
local max_count = tonumber(setup["数量"]) or 0
local tick_count = tonumber(setup["每次生成数量"]) or 1
if tick_count < 1 then tick_count = 1 end
if max_count > 0 and tick_count > max_count then
tick_count = max_count
end
type_of_grow_point:set_max_appera_count(max_count)
type_of_grow_point.tick_create_count = tick_count
local type_info = self:get_type_info_of_grow_point(gp_type)
if not type_info or not type_info["脚本ID"] then
skynet.logw("GrowPoint type_info or script_id not found for type:", gp_type)
type_of_grow_point.enable = false
else
type_of_grow_point.script_id = type_info["脚本ID"]
type_of_grow_point.enable = true
end
type_of_grow_point.org_interval = tonumber(setup["种子补充的间隔时间"]) or 0
type_of_grow_point.org_interval_inc = tonumber(setup["补充时间随机增量"]) or 0
type_of_grow_point.interval_per_seed = type_of_grow_point.org_interval
+ math.floor(type_of_grow_point.org_interval_inc * (math.random(100) - 1) / 100)
这里做了两件事:
- 把基础间隔和随机增量分别保存到:
org_interval
org_interval_inc
- 初始化时就按老 C++ 公式算出第一轮
interval_per_seed
如果只写成:
type_of_grow_point.interval_per_seed = setup["种子补充的间隔时间"]
那 补充时间随机增量 就彻底失效了。
7. 第三处修改:每轮补刷结束后重新随机下一轮时间
文件:
/ubuntu/Game2/lualib/growpointenginer.lua
最终 heart_beat() 关键代码如下:
function growpointenginer:heart_beat()
for _, type_of_grow_point in pairs(self.type_of_growpoints) do
if type_of_grow_point:do_ticks() then
local tick_count = type_of_grow_point.tick_create_count or 1
for _ = 1, tick_count do
local r, x, y = type_of_grow_point:create_grow_point_pos()
if not r then
break
end
if type_of_grow_point.script_id then
if not self:call_script_create_func(type_of_grow_point.script_id, x, y, type_of_grow_point:get_grow_point_type()) then
type_of_grow_point:release_grow_point_pos(x, y)
end
end
end
if tick_count > 1 and type_of_grow_point.script_id then
self:call_script_tick_create_finish_func(type_of_grow_point.script_id, type_of_grow_point:get_grow_point_type(), tick_count)
end
local org = type_of_grow_point.org_interval or 0
local inc = type_of_grow_point.org_interval_inc or 0
type_of_grow_point.interval_per_seed = org + math.floor(inc * (math.random(100) - 1) / 100)
end
end
end
这段代码的关键不是批量创建,而是最后这 3 行:
local org = type_of_grow_point.org_interval or 0
local inc = type_of_grow_point.org_interval_inc or 0
type_of_grow_point.interval_per_seed = org + math.floor(inc * (math.random(100) - 1) / 100)
意义是:
- 当前这一轮补刷完成后
- 立刻重新随机“下一轮要等多久”
- 和老 C++ 的
HeartBeat 行为保持一致
如果只在 load() 时算一次随机值,而不在这里重算,那么后续所有刷新都会退化成“固定间隔”。
9. 配置检查
优先找 补充时间随机增量 > 0 的场景验证,例如:
liaoxi_growpointsetup.txt
示例配置:
613 20 20 1800000 1200000
观察点:
- 刷新不是永远固定 1800000 ms
- 不同轮次之间间隔会波动
- 波动范围不会超过
补充时间随机增量