From daab95a1c599a884f22638f9472c6ab35d25b604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=A1=E5=87=AF?= <82950058@qq.com> Date: Sun, 28 Jun 2026 04:08:50 +0800 Subject: [PATCH] Refactor quest diary module loading and dispatch routing --- .../Mir200/Envir/Market_Def/QFunction-0.lua | 28 +- .../Mir200/Envir/QuestDiary/net/Message.lua | 5 +- .../Envir/QuestDiary/util/GameEvent.lua | 8 +- .../Envir/QuestDiary/util/ModuleLoader.lua | 256 ++++++++++++++++++ .../游戏功能/A1_一大陆/绝学修炼.lua | 6 +- 5 files changed, 277 insertions(+), 26 deletions(-) create mode 100644 Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua diff --git a/Mirserver/Mir200/Envir/Market_Def/QFunction-0.lua b/Mirserver/Mir200/Envir/Market_Def/QFunction-0.lua index dea0b4f6..53e2b663 100644 --- a/Mirserver/Mir200/Envir/Market_Def/QFunction-0.lua +++ b/Mirserver/Mir200/Envir/Market_Def/QFunction-0.lua @@ -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) diff --git a/Mirserver/Mir200/Envir/QuestDiary/net/Message.lua b/Mirserver/Mir200/Envir/QuestDiary/net/Message.lua index 746a1115..3cebf7c1 100644 --- a/Mirserver/Mir200/Envir/QuestDiary/net/Message.lua +++ b/Mirserver/Mir200/Envir/QuestDiary/net/Message.lua @@ -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 diff --git a/Mirserver/Mir200/Envir/QuestDiary/util/GameEvent.lua b/Mirserver/Mir200/Envir/QuestDiary/util/GameEvent.lua index 0f33bb6b..0c5b039c 100644 --- a/Mirserver/Mir200/Envir/QuestDiary/util/GameEvent.lua +++ b/Mirserver/Mir200/Envir/QuestDiary/util/GameEvent.lua @@ -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 diff --git a/Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua b/Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua new file mode 100644 index 00000000..629bc1d2 --- /dev/null +++ b/Mirserver/Mir200/Envir/QuestDiary/util/ModuleLoader.lua @@ -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 diff --git a/Mirserver/Mir200/Envir/QuestDiary/游戏功能/A1_一大陆/绝学修炼.lua b/Mirserver/Mir200/Envir/QuestDiary/游戏功能/A1_一大陆/绝学修炼.lua index bbb9b56c..8c2c0038 100644 --- a/Mirserver/Mir200/Envir/QuestDiary/游戏功能/A1_一大陆/绝学修炼.lua +++ b/Mirserver/Mir200/Envir/QuestDiary/游戏功能/A1_一大陆/绝学修炼.lua @@ -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