这篇单独讲 times_check,这是我在 2013 年为 sanc 导入的
新系统,它的最基本意义是减少心跳物件的使用量:
传统: 每一个需做心跳判断的物件都需要 set_heart_beat(1)
现在: 统一只由一个物件做 set_heart_beat(1),再让它去呼
叫其它物件的 heart_beat 或其它函数
(然后出发点都是要减少 call_out 的使用量)
我在 tmi2_v3_改 所写的 MYHOMD_D→every myhome 也是应用
相同的概念,因 myhome 不只一个附属系统所以让 MYHOME_D
去负责呼叫事宜。
times_check 的控制资料分为两部份
mapping times_check=([]); // 要存进 .o 的资料
static mapping times_no_save=([]); // 不存进 .o 的资料以 static 宣告
例如以 /std/boat.c 定期航班式交通工具为例,它会同时使
用到这两部份的资料:
times_check : 储存经过多久再回 call 航班设定的函数
times_no_save : 暂存航行资讯,由航班设定函数所产生:
n1 秒后执行哪些东西
n2 秒后执行哪些东西
.
.
> call times_check;check_names;"/d/area/test/boat"
times_check 区:
({ "/d/area/test/boat", "/d/area/test/boat", ({ "start_plane" }) }) 193 秒后.
经过 193 秒后回 call 航班设定函数并带 "start_plane" 参数过去
times_check_no_save 区:
底下就是由航班设定函数所产生的航班暂存资料,分别标示了几秒后
会带什么参数过去,/std/boat.c 就是靠这些参数来判断这时候应该
做什么事:
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_0_2" }) }) 13 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_0_3" }) }) 33 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_0_4" }) }) 53 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_0_5" }) }) 73 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_1_1" }) }) 93 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_1_2" }) }) 113 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_1_3" }) }) 133 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_1_4" }) }) 153 秒后.
({ "/d/area/test/boat", "/d/area/test/boat", ({ "plane_1_5" }) }) 173 秒后.
像上面那样子排序过后就很清楚,它就类似行事历,时间到了就做
什么事这样。
这样子设计的好处就是,“暂存”的资料是可以由“储存”的资料
产生,比方船只正在航行中我们却 update times_check.c 的话,
“最起码的”再经过多少秒之后它一定会再回 call 一次航班设定
函数。这里带出一个概念就是暂存的资料是可以丢弃的,反之不可
丢弃的就不要设定为暂存资料。
然后每一个想借由 times_check 做周期控制的物件,必定有底下的
片段:
> more /std/boat.c
static object times_check;
int times_check(string names,string files,mixed tmps)
{
// 继承用样本本身不需执行
if(names==BOAT) return 1;
// times_check 加载不成功的话绝对不执行
if(!times_check)
if(catch(times_check=find_object_or_load(TIMES_CHECK_OB)))
return 1;
然后假设我们设计 n 秒后会回 call 自己,则必定有底下片断:
// 先移掉旧的资料(这是保险起见,其实不见得要做)
times_check->remove_names(names);
// 再设定新的资料
times_check->set_times_check(names,files,({"start_plane"}),n秒);
至于 set_times_no_save 则支援两种呼叫方式:
// 一次只设定单笔
times_check->set_times_check(names,files,({"start_plane"}),秒数);
// 一次设定多笔
times_check->set_times_check(names,files,({
({ ({要传过去的参数群a}), 秒数a }),
({ ({要传过去的参数群b}), 秒数b }),
.
.
}),
);
例如底下 /std/boat.c 的设定范例
tmps+=({ ({ ({"plane_"+i+"_1"}),t }) }); // 停靠, 此时 t 为几秒后停靠
t=t+(int)planes[i][2]; // 累加时间
tmps+=({ ({ ({"plane_"+i+"_2"}),t}) }); // 广播, 此时 t 为几秒后广播
t=t+(int)planes[i][2]; // 再累加时间
.
.
然后我们就可以想像 times_check 可能储存了底下的资料
"时刻1": 要做什么事
"时刻2": 要做什么事
.
.
(时刻以字串型式储存)
则它的心跳函数架构就不难想像:
keys_times=keys(times_check);
t = time();
// 当现在时刻已超过或等于某一纪录的时刻时就做 something
foreach(tmp in keys_times)
{
if(t>=atoi(tmp))
{
do_check(times_check[tmp]);
// 做完就把该时刻纪录 delete 掉
map_delete(times_check,tmp);
}
}
目前在 sanc 除了船只之外,书店的定期阅读也是用 times_check:
static object times_check;
int times_check(string names,string files,mixed tmps)
{
int s,sk;
string str;
object ppl;
if(!times_check)
if(catch(times_check=find_object_or_load("/open/cmds/times_check")))
return 1;
if(!ppl=find_player(names)) return 1;
if(!interactive(ppl)) return 1;
str=base_name(environment(ppl));
if(str!=__DIR__+"room1" && str!=__DIR__+"room2" &&
str!=shop_files)
{
tell_object(ppl,HIC"* 你离开了书店,书店小姐将你租阅\的书收走囉。"NOR"\n");
return 1;
}
s=member_array(tmps[0],books);
sk=(int)ppl->query("skill/"+BOOKS[s][1]);
if(sk>=BOOKS[s][2][1])
{
tell_object(ppl,HIC"* 你已经不需要再在书店读《"+tmps[0]+"》囉!"NOR"\n");
return 1;
}
tell_object(ppl,"你阅\读了《"+tmps[0]+"》里头艰深的文字,得到了一些心得...\n");
ppl->improve_skill(BOOKS[s][1],(sk+(int)ppl->query("stat/int"))/10);
// 再设定回 call 资料
if(sk/10 > 300)
// 玩家 书店档 要传过去的参数群 秒数
times_check->set_times_check(names,shop_files,({tmps[0],sk}),sk/50);
else
times_check->set_times_check(names,shop_files,({tmps[0],sk}),sk/10);
return 1;
}
上面可发现它是使用了 names 及 shop_files 做为组合搭配,
这意思是说不同的 names、相同的 shop_files 是被允许的,
例如多人于书店阅读的情况:
书店内阅室
这里是设于书店一角的开放式内阅室,除了提供巫师们租借
书报杂志在里头阅读,也有简易的餐饮服务,舒适的大沙发
更是让你一看到就想窝著不动。
明显出口有: north 和 south.
(圣洁光芒) 希望(28957)正站在这里。
这是一本书(ThisIsABook)正站在这里。
(圣洁光芒) Celedia(Celedia:进阶法师)正站在这里。
(圣洁光芒) Kasim(Kasim:进阶法师)正站在这里。
而船只因为没有 names,但是因为每一艘船的 base_name 都是
独立的,所以就让 names = files = base_name(船只)。
当然,相同的 names,不同的 files 亦是被允许的。
times_check 可支援的其它常见系统举例:
料理制作、武防铸造、炼金炼药、闭关修练内功、...
这篇会存在 tmi2_v3_改 的 /d/area/times_check使用说明.txt
Laechan