出品人:Seagate
原帖地址:Cmud的时间控制小技巧
Zmud和Zmud的升级版Cmud总得来说时间控制上有些小麻烦, 主流的控制时间的模式有三种:Tick Timer、#wa系列语法、 #alarm触发器系列。相关使用方法可以参考Wiki里面一篇关于 时间控制的文章。这几天写一些Cmud相关的文章帮助大家了解 Zmud系列软件使用上的一些小技巧。可能有错误的地方请大家 发帖子纠正,或者有更好的办法也发帖子告诉我一下。
这是三种不同的方式,最稳定最容易控制的当然是Tick Timer了,但是Tick Timer资源是十分紧缺和有限的,如果你 要做一个长时间的自动机器人,可以把Tick Timer作为你的 纠错机制,每隔一段时间对你的机器人状态做一个判断,发 现处于未知状态就根据一定规则进行补偿处理使自己的机器 人回到正确轨道上来。建议最好不要把通用做法放在Tick Timer里面,Tick Timer的资源太珍贵了,通用命令完全可以 用#alarm触发器来实现。这方面做法比起Mush就差多了,Mush 用习惯了估计对麻烦的Zmud使用方式嗤之以鼻吧?不过我们使 用习惯了Zmud也只能适应了。
第二种方式是#wa系列语法,包括#wait,#waitfor, #waitsig,#waitthread。分别是等待一定时间,等待某一个 触发器,等待某一个信号量,等待某一个线程。由于#wa系列 语法都会引起多线程问题,所以在Cmud里面使用非常受限制, 你必须保证在使用#wa系列命令的时候没有使用全局变量,全 都是local变量,并且应用逻辑不能过于复杂,在这样子的环 境下使用#wa命令保证不容易出问题。但是如果你在alias里面 使用#wa,比如cmd1;#wa 500;cmd2;#wa 500;cmd3;#wa 500, 有时候并不会你感受到的那样子执行1.5秒才执行完整个命令 串,这一点在Zmud上非常明显,Cmud237上好很多,但是还是 有一些问题,总的来说变快了。如果你的多个触发中没有使用 全局变量,可以用#waitsign来控制多个触发之间的一致性。 举例来说:
#trigger {A} {cmd1;#signal sign1;cmd2;#waitsig sign2;cmd3} #trigger {B} {cmd4;#waitsig sign1;cmd4;#signal sign2;cmd6}
触发A和触发B同时被触发,那么cmd1和cmd4先执行,触发B要等 触发A发出信号sign1以后才能执行cmd4,触发A要等触发B发出信 号2以后才能执行cmd3。这个就是一种触发间比较精确的同步。
第三种是使用触发器来控制时间流程,#alarm触发器可以 提供非常灵活和精确的时间控制。比如#alarm +1 {cmd}, #alarm {1} {cmd}等等,既可以提供延迟触发,又可以提供循环 发命令,但是#alarm有一个缺点,他使用完马上就消失了,或 者如果有多个触发器控制一个相同的#alarm的话你无名捕捉他 的具体状态,有时候你又想精确控制他的状态。Zmud的时候处 理办法就是使用全局变量控制,判断全局变量的状态来处理。 Cmud有一个方便的办法是用Event。你可以这么做:
#alarm +0.5 {#raiseevent evtPerform}
你把Event:evtPerform给实现了,然后当你不想在触发 evtPerform的时候直接#t- evtPerform就可以了,不用管#alarm 时候会做多什么。
后续讨论
#waitsig用起来要小心。我没有在复杂代码用成功过,简单代码上目前我发现不等跑早了也就早了!关键是不能出现全局变量,这个对我挑战非常大。我没太想清楚该在什么场景下使用。#alarm+event可以给例子。
下面例子有2个触发,一个触发是镖车到了look启动房间检查和行走,第二个是房间检查通过发起hbRoomCheck时间进行检查。这个事件每给出代码,第二个是检查通过以后发起事件hbWalk行镖。如果行镖结束首先是#t-关闭hbWalk就不会再走了,关闭#alarm定时器是为了清理定时器,清理残留垃圾。实际上定时器在关闭事件以后就无效了。例子是xml文件,自己可以导入到Cmud看看。
例子如下:
<trigger priority="6614"> <pattern><![CDATA[^??你赶着镖车驶了过来。]]></pattern> <value><![CDATA[#t- hbWalk #unt fight_pfm #unt health_check #SECTION SingleThread { #va error_locate_list "" #va jingmo_cnt 0 #va fight_flag 0 #va fight_start_flag 0 #va quest_autoflag 1 } #t+ fight_trigger #alarm quest_auto {+8} {#va quest_autoflag 0} #if (@locate_pathid>=@target_pathid and @error_path_flag="START") { #va target_arr_flag 1 #t- walk_room_check #t- hbWalk #unt check_locate #alarm quest_search_huoji {+3} {set action 伙计搜索阶段一} } { #if (@error_path_flag!="ERROR") { #add locate_pathid 1 look } }]]></value> </trigger> <trigger name="walk_room_check" priority="6612" enabled="false"> <pattern>(*)-%s$</pattern> <value>#SECTION SingleThread { locate_desc=%trim(%1) locate_description="" locate_directlist="" }</value> <trigger param="20" regex="true" enabled="false"> <pattern>(.*)</pattern> <value>#SECTION SingleThread { locate_description=%trim(%1) }</value> </trigger> <trigger regex="true" enabled="false"> <pattern><![CDATA[\s+这里.*出口是(.*)]]></pattern> <value><![CDATA[//此处为走路行为判断的核心程序,主要处理三种情况的行走问题,第一种情况是正常行走未出现乱入情况, //并且本地地名和列表中存储的地名一致则不需要其他处理,正常根据已定义路径走到下一个地点就可以, //第二种情况是正常行走未出现乱入情况但是本地地名和列表中存储的地名不一致,这时候需要重新找回护 //镖路线,第三种情况是乱入到未知地点的情况下重新返回护镖路线。(具体返回护镖路线算法见核心批处理 //locate_redir的解释) #SECTION SingleThread { locate_directlist=%sort( %replace( %replace( %replace( %trim(%1), "。", ""), " 和 ", "|"), "、", "|")) } #local $rtn #if @error_path_flag="ERROR" { #t- hbWalk #raiseevent hbRoomCheck @locate_desc @locate_directlist @locate_description #waitsignal signCheckEnd #if @error_path_flag="ERROR" { #show "护镖任务:未能找到返回路线,请手工返回!" } } { room_desc=@room_info(%item( @hbnum_runtime, %eval( @locate_pathid-1))) $rtn=@compare_room(@room_desc,@locate_desc,@locate_directlist) #if $rtn=1 { #SECTION SingleThread { #va error_path_flag START } room_desc=@room_info(%item( @hbnum_runtime, @locate_pathid)) #WIN hubiao Locate:@locate_desc,Next Room:@room_desc.name,Next Pathid:@locate_pathid #t+ hbWalk #raiseevent hbWalk %item( @hbcmd_runtime, @locate_pathid) 1 #alarm check_locate {1} { #raiseevent hbWalk %item( @hbcmd_runtime, @locate_pathid) 1 } } { #raiseevent hbRoomCheck @locate_desc @locate_directlist @locate_description #waitsignal signCheckEnd #if @error_path_flag!="ERROR" { #va error_path_flag START } } }]]></value> </trigger> </trigger> <event event="hbWalk" priority="447910" enabled="false"> <value><![CDATA[#if (@target_pathid<@locate_pathid&&$mode=1) { #SECTION SingleThread { target_arr_flag=1 locate_pathid=@target_pathid } #t- walk_room_check #t- hbWalk #unt check_locate #alarm quest_search_huoji {+3} {set action 伙计搜索阶段一} } { #show $direct #SWITCH ($mode=0) { #exec gan che to $direct } ($mode=1) { #exec $direct } { #win hubiao 护镖任务:行走模式:$mode,有问题!行走命令:$direct } }]]></value> <arglist>$direct,$mode</arglist> </event>