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/util")
|
||||||
require("Envir/QuestDiary/util/提升基类")
|
require("Envir/QuestDiary/util/提升基类")
|
||||||
Message.dispatch_handler["GmBoxOBJ"] = require("Envir/QuestDiary/util/GM操作台")
|
ModuleLoader = require("Envir/QuestDiary/util/ModuleLoader")
|
||||||
Message.dispatch_handler["NPCGotoMapOBJ"] = require("Envir/QuestDiary/util/挂机地图传送")
|
ModuleLoader.reset()
|
||||||
Message.dispatch_handler["AutoXunHangOBJ"] = require("Envir/QuestDiary/util/自动巡航下图")
|
|
||||||
|
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
|
ModuleLoader.loadSystemDir("QuestDiary/系统类", "Envir/QuestDiary/系统类", "system")
|
||||||
local file = string.format("Envir/QuestDiary/%s/%s", "系统类", Func.splitString(v, ".")[1])
|
ModuleLoader.loadGameDirs("QuestDiary/游戏功能", "Envir/QuestDiary/游戏功能", "game")
|
||||||
require(file)
|
ModuleLoader.resolvePending()
|
||||||
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.loadModule("Envir/QuestDiary/util/系统任务", "postStart", { register = true })
|
||||||
require("Envir/QuestDiary/util/系统任务")
|
ModuleLoader.report()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,12 @@ function Message.dispatch(actor, msgID, arg1, arg2, arg3, str)
|
||||||
if not msgName then return end
|
if not msgName then return end
|
||||||
|
|
||||||
local module, method = msgName:match("([^.]*)_(.*)")
|
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 中注册的方法被前端调用
|
-- 白名单校验:只允许 allowFunc 中注册的方法被前端调用
|
||||||
local obj = _G[module]
|
|
||||||
if obj.allowFunc then
|
if obj.allowFunc then
|
||||||
local allowed = false
|
local allowed = false
|
||||||
for _, v in ipairs(obj.allowFunc) do
|
for _, v in ipairs(obj.allowFunc) do
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ function GameEvent.remove(func)
|
||||||
for i = 1, #eventListeners do
|
for i = 1, #eventListeners do
|
||||||
if eventListeners[i][1] == func then
|
if eventListeners[i][1] == func then
|
||||||
table.remove(eventListeners, i)
|
table.remove(eventListeners, i)
|
||||||
if 0 == #listeners[eventName] then
|
if 0 == #_listeners[eventName] then
|
||||||
listeners[eventName] = nil
|
_listeners[eventName] = nil
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -70,7 +70,7 @@ function GameEvent.removeByNameAndTag(eventName, tag)
|
||||||
end
|
end
|
||||||
|
|
||||||
if 0 == #eventListeners then
|
if 0 == #eventListeners then
|
||||||
listeners[eventName] = nil
|
_listeners[eventName] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ end
|
||||||
function GameEvent.removeByTag(tag)
|
function GameEvent.removeByTag(tag)
|
||||||
assert(tag, "Tag must not be nil")
|
assert(tag, "Tag must not be nil")
|
||||||
for eventName, eventListeners in pairs(_listeners) do
|
for eventName, eventListeners in pairs(_listeners) do
|
||||||
self.removeListenerByNameAndTag(eventName, tag)
|
GameEvent.removeByNameAndTag(eventName, tag)
|
||||||
end
|
end
|
||||||
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,
|
end,
|
||||||
[2] = function(actor, target, hitter, magicId, damage, model, Info)
|
[2] = function(actor, target, hitter, magicId, damage, model, Info)
|
||||||
if Player.CheckNPCRange(actor, target, 1) and magicId ~= 26 then
|
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
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -260,7 +260,7 @@ JueXueXiuLianOBJ.AttackdamageCfg = {
|
||||||
---* 使用刺杀剑术 有5%的概率提升刺杀剑术伤害10% 持续5秒
|
---* 使用刺杀剑术 有5%的概率提升刺杀剑术伤害10% 持续5秒
|
||||||
[5] = function(actor, target, hitter, magicId, damage, model, Info)
|
[5] = function(actor, target, hitter, magicId, damage, model, Info)
|
||||||
if magicId == 12 and not Player.CheckNPCRange(actor, target, 1) then
|
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)
|
addbuff(actor, 10001, 10)
|
||||||
-- Func.sendmsg(actor, string.format("[技能绝学]:#70|%s#215|触发,提升刺杀剑术伤害10%%,持续10s.#7", "撕裂长空"))
|
-- Func.sendmsg(actor, string.format("[技能绝学]:#70|%s#215|触发,提升刺杀剑术伤害10%%,持续10s.#7", "撕裂长空"))
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue