GameEvent = {}
local _listeners = {}
-- 添加事件派发
---*eventName: 事件名字
---*fun:要执行的函数
---*tag:备注
---*priority:优先级
function GameEvent.add(eventName, func, tag, priority)
assert(tag, "Tag must not be nil")
if not _listeners[eventName] then
_listeners[eventName] = {}
end
local eventListeners = _listeners[eventName]
local eventListenerSize = #eventListeners
for i = 1, eventListenerSize do
if tag == eventListeners[i][2] then
return
end
end
if priority and eventListenerSize >= priority then
table.insert(eventListeners, priority, {func, tag})
else
table.insert(eventListeners, {func, tag})
end
end
--[[
移除指定的事件监听器函数
@param func 要移除的监听器函数
工作流程:
1. 遍历所有事件类型
2. 在每个事件类型中查找匹配的监听器函数
3. 找到后移除该监听器
4. 如果事件类型的监听器列表为空,则移除该事件类型
]]
function GameEvent.remove(func)
-- 遍历所有事件类型及其监听器列表
for eventName, eventListeners in pairs(_listeners) do
-- 遍历当前事件类型的所有监听器
for i = 1, #eventListeners do
-- 如果找到匹配的监听器函数
if eventListeners[i][1] == func then
-- 移除该监听器
table.remove(eventListeners, i)
-- 如果该事件类型没有监听器了,清理该事件类型
if 0 == #listeners[eventName] then
listeners[eventName] = nil
end
-- 找到并处理完毕,直接返回
return
end
end
end
end
--[[
根据事件名和标签移除事件监听器
@param eventName 事件名称
@param tag 事件标签
工作流程:
1. 确保tag参数不为空
2. 获取指定事件名称的监听器列表
3. 从后向前遍历查找匹配的标签(从后向前遍历避免删除元素时影响索引)
4. 找到后移除该监听器并退出循环
5. 如果事件监听器列表为空,则清理该事件类型
]]
function GameEvent.removeByNameAndTag(eventName, tag)
-- 断言确保tag不为空
assert(tag, "Tag must not be nil")
-- 获取指定事件的监听器列表
local eventListeners = _listeners[eventName]
-- 如果该事件没有监听器,直接返回
if not eventListeners then return end
-- 从后向前遍历,避免删除元素时影响索引
for i = #eventListeners, 1, -1 do
-- 如果找到匹配的标签
if eventListeners[i][2] == tag then
-- 移除该监听器
table.remove(eventListeners, i)
break
end
end
-- 如果该事件类型没有监听器了,清理该事件类型
if 0 == #eventListeners then
listeners[eventName] = nil
end
end
--[[
根据标签移除所有相关的事件监听器
@param tag 事件标签
工作流程:
1. 确保tag参数不为空
2. 遍历所有事件类型
3. 对每个事件类型调用removeListenerByNameAndTag移除指定标签的监听器
使用场景:
- 当需要清理某个模块的所有事件监听时
- 模块卸载时清理相关事件
- 批量移除某个标签下的所有监听器
]]
function GameEvent.removeByTag(tag)
assert(tag, "Tag must not be nil")
for eventName, eventListeners in pairs(_listeners) do
GameEvent.removeListenerByNameAndTag(eventName, tag)
end
end
function GameEvent.removeAll()
_listeners = {}
end
--[[
发布事件并执行所有注册的监听器
@param eventName 事件名称
@param ... 可变参数,传递给事件监听器的参数
工作流程:
1. 获取指定事件名称的所有监听器
2. 如果没有监听器,直接返回
3. 按优先级顺序遍历执行所有监听器
4. 使用pcall安全调用每个监听器
5. 支持监听器通过返回true来中断事件传播
6. 处理执行错误并输出错误信息
]]
function GameEvent.push(eventName, ...)
-- 获取事件对应的监听器列表
local eventListeners = _listeners[eventName]
-- 如果没有监听器,直接返回
if not eventListeners then
return
end
-- 遍历执行所有监听器
for index, listeners in ipairs(eventListeners) do
-- 使用pcall安全调用监听器函数
-- result: 执行是否成功
-- stop: 监听器的返回值,用于控制事件传播
local result, stop = pcall(listeners[1], ...)
if result then
-- 如果监听器返回true,停止事件传播
if stop then break end
else
-- 执行出错时,获取错误信息
local tag = listeners[2]
local tarid = tag.ID or 0
-- 构建错误信息,包含事件名和模块ID
local err = "派发事件发生错误:事件名="..eventName.." 模块ID="..tarid.." "
-- 输出错误日志
release_print(err, stop)
end
end
end
return GameEvent