杰哥瞎扯蛋之 事件系统的优化
本帖最后由 jarlyyn 于 2024-10-15 02:24 PM 编辑新机器人的新任务模块做好了,跑稳定性测试,正好再水一帖。
之前我提过 mud事件系统,见
https://www.pkuxkx.net/forum/thread-49068-1-1.html
这次做框架时做了小优化。
我之前说过,事件系统最大的优点时解耦,最大的缺点时执行顺序不定。无法避免重复触发。
这个我优化不掉,优点既缺点。
但我在新的框架里提供3个新的机制,使得代码里能适当的避开这些缺点。
1.为每个发起的事件提供了上下文(Context),可以在每次发起时提供一个数据空间,让相应函数之间有交互的基础。
参考代码:
task.AddTrigger(matcherOnHeal, function (trigger, result, event) {
let item = new objectModule.Object(result, "", App.History.CurrentOutput).
WithParam("动作", "result")
App.Map.Room.Data.Objects.Append(item)
event.Context.Set("core.room.onobject", true)
return true
})
task.AddCatcher("line", function (catcher, event) {
return event.Context.Get("core.room.onobject")
})
在触发器里,匹配过的行会设置"core.room.onobject"属性。
这样,当在事件捕捉期里,由于处理的是同一个事件,就能避免重复处理以及冲突了。
2.为事件自带了默认的生命周期,使得虽然事件的绑定程序顺序不定,但可以将处理程序绑在事件上,按不同的优先级处理。
具体看代码
事件的代码
Propose(callback){
return this.#propose(this.#proposals,callback)
}
ProposeEarly(callback){
return this.#propose(this.#proposalsEarly,callback)
}
ProposeEarlier(callback){
return this.#propose(this.#proposalsEarlier,callback)
}
ProposeLate(callback){
return this.#propose(this.#proposalsLate,callback)
}
ProposeLater(callback){
return this.#propose(this.#proposalsLater,callback)
}
Execute(){
.forEach(proposals => {
proposals.forEach(hook=>{
hook()
})
});
}
#propose(proposals,callback) {
proposals.push(callback)
return true
}
很明显,我给事件的上下文了挂了proposal这个东西,同时有Earlier,Early,普通,Late,Later5个阶段,同时配合立刻执行,等于6了六个执行优先级,一般也够用了。
典型的应用场景是
App.BindEvent("core.roomentry", function (event) {
event.Context.ProposeLater(function () {
App.Map.OnWalking()
})
})
在进入房间后,先确保其他事件都执行了(典型就是确定当前房间的id),最后再调用移动模块,确认移动完成。
3.确保事件是异步的,避免不必要的期待。
我的主事件调用函数是这样的
OnEvent(event) {
this.#pendingEvents.push(event)
if (this.#pendingEvents.length > 1){
return
}
while (this.#pendingEvents.length > 0) {
let current=this.#pendingEvents
this.EventBus.RaiseEvent(current)
this.#eventHandlers.forEach(handler => {
handler.Handler(current)
})
current.Context.Execute()
this.#pendingEvents.shift()
}
}
新Raise的事件会压入pending,等当前事件处理完毕后
目的很明确避免,事件中调用事件造成事件执行数序的不可控。
当然,这也有缺点,必须直到事件调用是异步的,不能用传统的 初始化数据,发起构建事件,获取构建后的数据的流程(比如行走前更新更走的tag)。
有的必有失,没有银弹,只有tradeoff,没有办法。
然后是事件的发起方式,纯粹的代码发起不算。
我写了两个函数,
App.LineEvent和App.FilterLineEvent
LineEvent(eventname) {
let self = this;
return function (name, output, wildcards) {
let event = new self.#eventmodule.Event(eventname, {
Name: name,
Output: output,
Wildcards: wildcards,
}).WithType("line")
self.OnEvent(event)
}
}
FilterLineEvent(filtername, eventname) {
let filter = this.#filters
if (filter) {
let self = this;
return function (name, output, wildcards) {
let event = new self.#eventmodule.Event(eventname, {
Name: name,
Output: output,
Wildcards: wildcards,
}).WithType("line")
filter(event)
}
}
}
LineEvent是生成一个客户端回调,直接抛出一个指定的触发事件
FilterLineEvent是调用一个判断函数,可以再处理后抛出一个触发事件。
举个例子,大概是这样
App.Engine.SetFilter("core.normalroomname", function (event) {
let words = App.History.CurrentOutput.Words
if (words.length == 1 && words.Color == "Cyan" && words.Bold == true) {
App.RaiseEvent(event)
}
})
匹配文字,然后判断是否都是指定颜色,是指定颜色再抛出core.roomname事件。
这样可以很直接的弱化客户端的触发器功能。
基本我的触发器是这个画风
响应的代码都不要再写,维护起来十分轻松。
论坛编辑器的格式没救了……
这次就更新刀这里,看机器人稳定性去了。
下次正常应该更新新的行走模块。
页:
[1]