GameEvent = {}
local _listeners = {}
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]
我是lua后端老师!
小仙,你这个事件系统框架设计得很不错啊!让我先帮你分析一下这个框架:
你这个`GameEvent`模块是一个典型的事件监听/派发系统,主要功能包括:
- `add` - 添加事件监听器
- `remove` - 移除监听器
- `removeByNameAndTag` - 按事件名和标签移除
- `removeByTag` - 按标签移除所有监听器
- `removeAll` - 移除所有监听器
- `push` - 派发事件
现在你想要一个带返回值的事件系统,我来帮你改造一下。主要思路是让事件监听器可以返回值,然后在派发时收集这些返回值:
```lua
GameEvent = {}
local _listeners = {}
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
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 == #eventListeners then
_listeners[eventName] = nil
end
return
end
end
end
end
function GameEvent.removeByNameAndTag(eventName, 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
function GameEvent.removeByTag(tag)
assert(tag, "Tag must not be nil")
for eventName, eventListeners in pairs(_listeners) do
GameEvent.removeByNameAndTag(eventName, tag)
end
end
function GameEvent.removeAll()
_listeners = {}
end
-- 原push函数保持不变
function GameEvent.push(eventName, ...)
local eventListeners = _listeners[eventName]
if not eventListeners then
return
end
for index, listeners in ipairs(eventListeners) do
release_print("事件名:" .. eventName)
local result, stop = pcall(listeners[1], ...)
if result then
if stop then break end
else
local tag = listeners[2]
local tarid
if type(tag) == "string" then
tarid = tag
else
tarid = tag.ID or 0
end
local err = "派发事件发生错误:事件名=" .. eventName .. " 模块ID=" .. tarid .. " "
release_print(err, stop)
end
end
end
-- 新增:带返回值的事件派发函数
function GameEvent.pushWithReturn(eventName, ...)
local eventListeners = _listeners[eventName]
if not eventListeners then
return {}
end
local results = {} -- 存储所有监听器的返回值
for index, listeners in ipairs(eventListeners) do
release_print("事件名:" .. eventName .. ",开始执行监听器" .. index)
local success, result, stop = pcall(listeners[1], ...)
if success then
-- 将返回值存入结果表
table.insert(results, result)
-- 如果监听器返回true作为第二个值,表示停止后续监听器执行
if stop then
release_print("事件名:" .. eventName .. ",监听器" .. index .. "要求停止后续执行")
break
end
else
local tag = listeners[2]
local tarid
if type(tag) == "string" then
tarid = tag
else
tarid = tag.ID or 0
end
local err = "派发事件发生错误:事件名=" .. eventName .. " 模块ID=" .. tarid .. " "
release_print(err, result)
-- 错误时也记录一个特殊值
table.insert(results, {error = true, message = result})
end
end
return results -- 返回所有监听器的结果
end
-- 新增:带返回值且可中断的事件派发(返回第一个非nil结果)
function GameEvent.pushWithFirstReturn(eventName, ...)
local eventListeners = _listeners[eventName]
if not eventListeners then
return nil
end
for index, listeners in ipairs(eventListeners) do
release_print("事件名:" .. eventName .. ",开始执行监听器" .. index)
local success, result, stop = pcall(listeners[1], ...)
if success then
-- 如果监听器有返回值(非nil),则立即返回
if result ~= nil then
release_print("事件名:" .. eventName .. ",监听器" .. index .. "返回有效值,中断执行")
return result
end
-- 如果监听器要求停止
if stop then
release_print("事件名:" .. eventName .. ",监听器" .. index .. "要求停止后续执行")
break
end
else
local tag = listeners[2]
local tarid
if type(tag) == "string" then
tarid = tag
else
tarid = tag.ID or 0
end
local err = "派发事件发生错误:事件名=" .. eventName .. " 模块ID=" .. tarid .. " "
release_print(err, result)
end
end
return nil -- 所有监听器都没有返回有效值
end
return GameEvent
```
小仙,我给你增加了两个新的函数:
1. **`pushWithReturn`函数**:
- 会收集所有监听器的返回值,放入一个表中返回
- 每个监听器的返回值都会按顺序存入结果表
- 如果监听器执行出错,会在结果表中记录错误信息
2. **`pushWithFirstReturn`函数**:
- 一旦有监听器返回非nil值,就立即返回该值并中断后续监听器执行
- 适用于需要获取第一个有效结果的场景
**使用示例**:
```lua
-- 添加监听器
GameEvent.add("玩家升级", function(player, newLevel)
release_print(player .. "升级到" .. newLevel .. "级")
return {经验奖励 = 1000, 金币奖励 = 500} -- 返回一个表
end, "升级系统", 1)
GameEvent.add("玩家升级", function(player, newLevel)
if newLevel >= 50 then
return {称号 = "江湖高手"} -- 返回另一个表
end
return nil
end, "称号系统", 2)
-- 使用带返回值的事件派发
local results = GameEvent.pushWithReturn("玩家升级", "玩家1", 55)
-- results 会包含两个监听器的返回值
-- 或者使用获取第一个返回值
local firstResult = GameEvent.pushWithFirstReturn("玩家升级", "玩家1", 55)
-- 如果第一个监听器返回非nil值,就获取该值
```
这样改造后,你的事件系统就支持返回值了,可以根据不同的业务场景选择使用哪个函数。有什么不明白的可以继续问我哦!