Refactor quest diary module loading and dispatch routing
This commit is contained in:
parent
631e459606
commit
daab95a1c5
5 changed files with 277 additions and 26 deletions
|
|
@ -40,26 +40,20 @@ local _, errinfo = pcall(function()
|
|||
-- 通用模块
|
||||
require("Envir/QuestDiary/util/util")
|
||||
require("Envir/QuestDiary/util/提升基类")
|
||||
Message.dispatch_handler["GmBoxOBJ"] = require("Envir/QuestDiary/util/GM操作台")
|
||||
Message.dispatch_handler["NPCGotoMapOBJ"] = require("Envir/QuestDiary/util/挂机地图传送")
|
||||
Message.dispatch_handler["AutoXunHangOBJ"] = require("Envir/QuestDiary/util/自动巡航下图")
|
||||
ModuleLoader = require("Envir/QuestDiary/util/ModuleLoader")
|
||||
ModuleLoader.reset()
|
||||
|
||||
ModuleLoader.loadModule("Envir/QuestDiary/util/GM操作台", "system", { register = true })
|
||||
ModuleLoader.loadModule("Envir/QuestDiary/util/挂机地图传送", "system", { register = true })
|
||||
ModuleLoader.loadModule("Envir/QuestDiary/util/自动巡航下图", "system", { register = true })
|
||||
|
||||
-- 初始化游戏内容所有文件
|
||||
for i, v in ipairs(GetFileList(string.format("QuestDiary/%s", "系统类")) or {}) do
|
||||
local file = string.format("Envir/QuestDiary/%s/%s", "系统类", Func.splitString(v, ".")[1])
|
||||
require(file)
|
||||
end
|
||||
for i, v in ipairs(GetFileList(string.format("QuestDiary/%s", "游戏功能")) or {}) do
|
||||
local path = string.format("QuestDiary/%s/%s", "游戏功能", v)
|
||||
for _, file in ipairs(GetFileList(path) or {}) do
|
||||
local file_str = string.format("Envir/%s/%s", path, Func.splitString(file, ".")[1])
|
||||
local ssr = require(file_str)
|
||||
Message.dispatch_handler[ssr._name] = ssr
|
||||
end
|
||||
end
|
||||
ModuleLoader.loadSystemDir("QuestDiary/系统类", "Envir/QuestDiary/系统类", "system")
|
||||
ModuleLoader.loadGameDirs("QuestDiary/游戏功能", "Envir/QuestDiary/游戏功能", "game")
|
||||
ModuleLoader.resolvePending()
|
||||
|
||||
|
||||
require("Envir/QuestDiary/util/系统任务")
|
||||
ModuleLoader.loadModule("Envir/QuestDiary/util/系统任务", "postStart", { register = true })
|
||||
ModuleLoader.report()
|
||||
end)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,11 +41,12 @@ function Message.dispatch(actor, msgID, arg1, arg2, arg3, str)
|
|||
if not msgName then return end
|
||||
|
||||
local module, method = msgName:match("([^.]*)_(.*)")
|
||||
if not module or not method then return end
|
||||
|
||||
if not _G[module] then return end
|
||||
local obj = Message.dispatch_handler[module]
|
||||
if not obj then return end
|
||||
|
||||
-- 白名单校验:只允许 allowFunc 中注册的方法被前端调用
|
||||
local obj = _G[module]
|
||||
if obj.allowFunc then
|
||||
local allowed = false
|
||||
for _, v in ipairs(obj.allowFunc) do
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ function GameEvent.remove(func)
|
|||
for i = 1, #eventListeners do
|
||||
if eventListeners[i][1] == func then
|
||||
table.remove(eventListeners, i)
|
||||
if 0 == #listeners[eventName] then
|
||||
listeners[eventName] = nil
|
||||
if 0 == #_listeners[eventName] then
|
||||
_listeners[eventName] = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
|
|
@ -70,7 +70,7 @@ function GameEvent.removeByNameAndTag(eventName, tag)
|
|||
end
|
||||
|
||||
if 0 == #eventListeners then
|
||||
listeners[eventName] = nil
|
||||
_listeners[eventName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ end
|
|||
function GameEvent.removeByTag(tag)
|
||||
assert(tag, "Tag must not be nil")
|
||||
for eventName, eventListeners in pairs(_listeners) do
|
||||
self.removeListenerByNameAndTag(eventName, tag)
|
||||
GameEvent.removeByNameAndTag(eventName, tag)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
256
Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua
Normal file
256
Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
ModuleLoader = ModuleLoader or {}
|
||||
|
||||
ModuleLoader.loaded = ModuleLoader.loaded or {}
|
||||
ModuleLoader.failed = ModuleLoader.failed or {}
|
||||
ModuleLoader.skipped = ModuleLoader.skipped or {}
|
||||
ModuleLoader.pending = ModuleLoader.pending or {}
|
||||
ModuleLoader.modules = ModuleLoader.modules or {}
|
||||
ModuleLoader.modulePaths = ModuleLoader.modulePaths or {}
|
||||
ModuleLoader.phaseStats = ModuleLoader.phaseStats or {}
|
||||
|
||||
local function _log(...)
|
||||
if release_print then
|
||||
release_print(...)
|
||||
elseif LOGPrint then
|
||||
LOGPrint(...)
|
||||
else
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function _traceback(err)
|
||||
return tostring(err) .. "\n" .. debug.traceback("", 2)
|
||||
end
|
||||
|
||||
local function _shortError(err)
|
||||
local msg = tostring(err or "")
|
||||
local firstLine = msg:match("([^\n\r]+)") or msg
|
||||
local lineInfo = msg:match("([^\n\r]-%.lua:%d+:%s*[^\n\r]+)")
|
||||
return lineInfo or firstLine
|
||||
end
|
||||
|
||||
local function _push(list, item)
|
||||
list[#list + 1] = item
|
||||
end
|
||||
|
||||
local function _recordPhase(phase, key)
|
||||
local stat = ModuleLoader.phaseStats[phase]
|
||||
if not stat then
|
||||
stat = { success = 0, failed = 0, skipped = 0 }
|
||||
ModuleLoader.phaseStats[phase] = stat
|
||||
end
|
||||
stat[key] = (stat[key] or 0) + 1
|
||||
end
|
||||
|
||||
local function _basename(path)
|
||||
local name = tostring(path or "")
|
||||
name = name:gsub("\\", "/")
|
||||
name = name:match("([^/]+)$") or name
|
||||
name = name:gsub("%.lua$", "")
|
||||
return name
|
||||
end
|
||||
|
||||
local function _safeName(module, path)
|
||||
if type(module) == "table" and module._name and module._name ~= "" then
|
||||
return tostring(module._name)
|
||||
end
|
||||
return _basename(path)
|
||||
end
|
||||
|
||||
local function _dependsReady(depends)
|
||||
if not depends then
|
||||
return true
|
||||
end
|
||||
if type(depends) ~= "table" then
|
||||
return false, "_depends must be table"
|
||||
end
|
||||
for _, name in ipairs(depends) do
|
||||
if not ModuleLoader.modules[name] then
|
||||
return false, "missing dependency: " .. tostring(name)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ModuleLoader.reset()
|
||||
ModuleLoader.loaded = {}
|
||||
ModuleLoader.failed = {}
|
||||
ModuleLoader.skipped = {}
|
||||
ModuleLoader.pending = {}
|
||||
ModuleLoader.modules = {}
|
||||
ModuleLoader.modulePaths = {}
|
||||
ModuleLoader.phaseStats = {}
|
||||
end
|
||||
|
||||
function ModuleLoader.getFiles(dir)
|
||||
local ok, files = xpcall(function()
|
||||
return GetFileList(dir) or {}
|
||||
end, _traceback)
|
||||
if not ok then
|
||||
_push(ModuleLoader.failed, { phase = "scan", path = dir, error = files })
|
||||
_log("[ModuleLoader] 扫描失败:", dir, files)
|
||||
return {}
|
||||
end
|
||||
table.sort(files, function(a, b)
|
||||
return tostring(a) < tostring(b)
|
||||
end)
|
||||
return files
|
||||
end
|
||||
|
||||
function ModuleLoader.safeRequire(path, phase)
|
||||
phase = phase or "default"
|
||||
local ok, module = xpcall(function()
|
||||
return require(path)
|
||||
end, _traceback)
|
||||
|
||||
if not ok then
|
||||
_push(ModuleLoader.failed, { phase = phase, path = path, error = module, short = _shortError(module) })
|
||||
_recordPhase(phase, "failed")
|
||||
_log("[ModuleLoader] 加载失败:", path, _shortError(module))
|
||||
return nil, module
|
||||
end
|
||||
|
||||
_push(ModuleLoader.loaded, { phase = phase, path = path, module = module })
|
||||
_recordPhase(phase, "success")
|
||||
return module
|
||||
end
|
||||
|
||||
function ModuleLoader.registerModule(module, path, phase, opts)
|
||||
opts = opts or {}
|
||||
phase = phase or "default"
|
||||
if type(module) ~= "table" then
|
||||
return true
|
||||
end
|
||||
|
||||
if module._enabled == false then
|
||||
_push(ModuleLoader.skipped, { phase = phase, path = path, reason = "disabled" })
|
||||
_recordPhase(phase, "skipped")
|
||||
return false, "disabled"
|
||||
end
|
||||
|
||||
local name = _safeName(module, path)
|
||||
local ready, reason = _dependsReady(module._depends)
|
||||
if not ready then
|
||||
if opts.deferMissing then
|
||||
return false, reason, "defer"
|
||||
end
|
||||
_push(ModuleLoader.skipped, { phase = phase, path = path, name = name, reason = reason })
|
||||
_recordPhase(phase, "skipped")
|
||||
_log("[ModuleLoader] 跳过模块:", name, reason)
|
||||
return false, reason
|
||||
end
|
||||
|
||||
if ModuleLoader.modules[name] then
|
||||
local err = "duplicate module name: " .. name .. ", old=" .. tostring(ModuleLoader.modulePaths[name]) .. ", new=" .. tostring(path)
|
||||
_push(ModuleLoader.failed, { phase = phase, path = path, name = name, error = err })
|
||||
_recordPhase(phase, "failed")
|
||||
_log("[ModuleLoader] 模块重名:", err)
|
||||
return false, err
|
||||
end
|
||||
|
||||
if type(module.init) == "function" then
|
||||
local ok, err = xpcall(function()
|
||||
module:init()
|
||||
end, _traceback)
|
||||
if not ok then
|
||||
_push(ModuleLoader.failed, { phase = phase, path = path, name = name, error = err, short = _shortError(err) })
|
||||
_recordPhase(phase, "failed")
|
||||
_log("[ModuleLoader] 初始化失败:", name, _shortError(err))
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
|
||||
ModuleLoader.modules[name] = module
|
||||
ModuleLoader.modulePaths[name] = path
|
||||
|
||||
if Message and Message.dispatch_handler and module._name and module._name ~= "" then
|
||||
Message.dispatch_handler[module._name] = module
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ModuleLoader.loadModule(path, phase, opts)
|
||||
opts = opts or {}
|
||||
local module, err = ModuleLoader.safeRequire(path, phase)
|
||||
if not module then
|
||||
return nil, err
|
||||
end
|
||||
if opts.register ~= false then
|
||||
local ok, reason, code = ModuleLoader.registerModule(module, path, phase, { deferMissing = true })
|
||||
if not ok and code == "defer" then
|
||||
_push(ModuleLoader.pending, { phase = phase, path = path, module = module, reason = reason })
|
||||
end
|
||||
end
|
||||
return module
|
||||
end
|
||||
|
||||
function ModuleLoader.resolvePending()
|
||||
local changed = true
|
||||
while changed do
|
||||
changed = false
|
||||
for i = #ModuleLoader.pending, 1, -1 do
|
||||
local item = ModuleLoader.pending[i]
|
||||
local ok = ModuleLoader.registerModule(item.module, item.path, item.phase, { deferMissing = true })
|
||||
if ok then
|
||||
table.remove(ModuleLoader.pending, i)
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = #ModuleLoader.pending, 1, -1 do
|
||||
local item = ModuleLoader.pending[i]
|
||||
ModuleLoader.registerModule(item.module, item.path, item.phase, { deferMissing = false })
|
||||
table.remove(ModuleLoader.pending, i)
|
||||
end
|
||||
end
|
||||
|
||||
function ModuleLoader.loadSystemDir(dir, requirePrefix, phase)
|
||||
local files = ModuleLoader.getFiles(dir)
|
||||
for _, file in ipairs(files) do
|
||||
if tostring(file):match("%.lua$") then
|
||||
local name = _basename(file)
|
||||
ModuleLoader.loadModule(requirePrefix .. "/" .. name, phase, { register = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ModuleLoader.loadGameDirs(rootDir, requirePrefix, phase)
|
||||
local dirs = ModuleLoader.getFiles(rootDir)
|
||||
for _, dir in ipairs(dirs) do
|
||||
local subDir = rootDir .. "/" .. dir
|
||||
local files = ModuleLoader.getFiles(subDir)
|
||||
for _, file in ipairs(files) do
|
||||
if tostring(file):match("%.lua$") then
|
||||
local name = _basename(file)
|
||||
ModuleLoader.loadModule(requirePrefix .. "/" .. dir .. "/" .. name, phase, { register = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ModuleLoader.report()
|
||||
local success = #ModuleLoader.loaded
|
||||
local failed = #ModuleLoader.failed
|
||||
local skipped = #ModuleLoader.skipped
|
||||
_log("[ModuleLoader] 启动报告: success=", success, " failed=", failed, " skipped=", skipped)
|
||||
|
||||
for phase, stat in pairs(ModuleLoader.phaseStats) do
|
||||
_log("[ModuleLoader] 阶段:", phase, " success=", stat.success or 0, " failed=", stat.failed or 0, " skipped=", stat.skipped or 0)
|
||||
end
|
||||
|
||||
if failed > 0 then
|
||||
for _, item in ipairs(ModuleLoader.failed) do
|
||||
_log("[ModuleLoader] 失败模块:", item.phase or "", item.path or "", item.name or "", item.short or _shortError(item.error))
|
||||
end
|
||||
end
|
||||
|
||||
if skipped > 0 then
|
||||
for _, item in ipairs(ModuleLoader.skipped) do
|
||||
_log("[ModuleLoader] 跳过模块:", item.phase or "", item.path or "", item.name or "", item.reason or "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ModuleLoader
|
||||
|
|
@ -249,9 +249,9 @@ JueXueXiuLianOBJ.AttackdamageCfg = {
|
|||
end,
|
||||
[2] = function(actor, target, hitter, magicId, damage, model, Info)
|
||||
if Player.CheckNPCRange(actor, target, 1) and magicId ~= 26 then
|
||||
if Func.random(5) and not hasbuff(actor, 10000) then
|
||||
if Func.random(100) and not hasbuff(actor, 10000) then
|
||||
if addbuff(actor, 10000, 5) then
|
||||
-- Func.sendmsg(actor, string.format("[技能绝学]:#70|%s#215|触发,忽视目标100%防御,持续5s.#7", "百步穿杨"))
|
||||
-- Func.sendmsg(actor, string.format("[技能绝学]:#70|%s#215|触发,忽视目标100%%防御,持续5s.#7", "百步穿杨"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -260,7 +260,7 @@ JueXueXiuLianOBJ.AttackdamageCfg = {
|
|||
---* 使用刺杀剑术 有5%的概率提升刺杀剑术伤害10% 持续5秒
|
||||
[5] = function(actor, target, hitter, magicId, damage, model, Info)
|
||||
if magicId == 12 and not Player.CheckNPCRange(actor, target, 1) then
|
||||
if Func.random(5) and not hasbuff(actor, 10001) then
|
||||
if Func.random(100) and not hasbuff(actor, 10001) then
|
||||
addbuff(actor, 10001, 10)
|
||||
-- Func.sendmsg(actor, string.format("[技能绝学]:#70|%s#215|触发,提升刺杀剑术伤害10%%,持续10s.#7", "撕裂长空"))
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue