尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

金庸群侠传3D重制版 LuaScripts 模块化开发指南:从全局表 Jyx2 到 Mod 覆盖机制

金庸群侠传3D重制版 LuaScripts 模块化开发指南:从全局表 Jyx2 到 Mod 覆盖机制 金庸群侠传3D重制版 LuaScripts 模块化开发指南从全局表 Jyx2 到 Mod 覆盖机制【免费下载链接】jynewJinYongLegend-like RPG Game Framework with full Modding support and 10 hours playable samples of game.项目地址: https://gitcode.com/GitHub_Trending/jy/jynew本指南以 jyx2/Assets/LuaScripts/README.md 为核心骨架系统讲解金庸群侠传3D重制版jynew中 LuaScripts 目录的模块化架构、Jyx2全局表的加载/调用机制、LuaModuleList模块注册表的使用方式以及如何在 Mod 中通过 Lua 文件覆盖游戏框架逻辑。文中所有接口说明均对照 InitLuaScripts.lua 与 LuaModuleList.lua 的源码逐一印证并给出可直接复制的模块注册与加载示例帮助你快速上手 Lua 侧的二次开发与调试。一、LuaScripts 在游戏框架中的定位在金庸群侠传3D重制版中Lua 是承载游戏业务逻辑的重要语言层。jyx2/Assets/LuaScripts/目录是游戏框架内置 Lua 脚本的存放位置承担着游戏功能模块 Lua 化的使命目前已经实现了Jyx2Configs配置表模块与Jyx2Battle战斗模块两个模块其余模块正在逐步迁移中。从 C# 侧的资源加载链路可以确认它的启动时机在 Jyx2ResourceHelper.cs 中资源初始化流程依次执行LuaManager.Init(...)创建 XLua 虚拟机并执行根 Lua 文件、InitLuaScripts()加载并执行Assets/LuaScripts/InitLuaScripts.lua随后初始化 Lua 到 C# 的桥接LuaToCsBridge、InitConfigTables()加载配置表与LuaManager.PreloadLua()执行热更新脚本。也就是说LuaScripts是游戏逻辑在 Lua 层的引导程序它的初始化发生在配置表加载之前为后续所有 Lua 模块提供了统一的加载入口和运行时环境。二、LuaScripts 目录结构与模块化设计LuaScripts采用模块化结构组织核心由四类文件构成文件职责InitLuaScripts.lua总入口脚本在LuaManager初始化时自动调用LuaModuleList.lua模块注册表保存模块名称 → 模块主文件路径的映射Jyx2Configs/已 Lua 化的配置模块Jyx2ConfigMgr.lua及若干 HelperJyx2Battle/已 Lua 化的战斗模块BattleInit.lua及其子模块LuaTestStarter.assetLua 代码调试器资产用于在 Inspector 中批量测试脚本模块化的设计意图非常明确入口脚本只负责注册与初始化具体业务以模块为单位解耦。InitLuaScripts.lua中通过require LuaModuleList读取注册表而模块主文件如Jyx2ConfigMgr.lua、BattleInit.lua各自返回一个 Lua table注册到全局表Jyx2下之后业务代码只需通过Jyx2.模块名即可访问。三、全局表 Jyx2所有 Lua 模块的统一容器Jyx2是一个全局 table储存所有已加载的 Lua 模块并提供加载与调用的方法。它的定义与实现位于 InitLuaScripts.lualocal requireList require LuaModuleList Jyx2 {} -- 所有 Lua 模块都作为 Jyx2 表的元素添加进去 Jyx2.moduleList {} -- 模块列表记录已加载模块名供反初始化遍历脚本开头有一段防重复定义保护如果Jyx2已经存在则直接print(Jyx2 重复定义)并return避免在编辑器热重载等场景下覆盖全局状态。3.1 Jyx2:AddModule(name, path) —— 手动加载模块签名Jyx2:AddModule(name, path)手动加载主文件路径为path的模块并命名为name如果省略path参数则默认从LuaModuleList注册表中查找名称为name的模块并加载模块已存在时不重复加载只会在未加载时执行require(path)成功后写入self[name]并追加到self.moduleList。对应源码实现InitLuaScripts.luafunction Jyx2:AddModule(name, path) -- 如果没指定模块地址则从表中获取 if path nil then path requireList[name] end local tmpMdl self[name] if tmpMdl nil then tmpMdl require(path) if tmpMdl nil then print(Jyx2-Error: 添加模块 ..name.. 失败) end print(Jyx2 增加模块: ..name) self[name] tmpMdl table.insert(self.moduleList, name) end end值得注意的实现细节require失败时仅打印错误而不会抛出异常中断流程因此建议在调用后通过Jyx2:IsLoaded(name)校验加载结果。3.2 Jyx2:GetModule(name) —— 获取模块带自动加载签名Jyx2:GetModule(name)返回名称为name的模块。与直接访问Jyx2.name的区别在于如果模块尚未加载GetModule会根据LuaModuleList中的路径自动加载。function Jyx2:GetModule(name) local tmpMdl self[name] if tmpMdl ~ nil then return tmpMdl else self:AddModule(name) -- path 为 nil走注册表查找 return self[name] end return nil end3.3 Jyx2:IsLoaded(name) —— 查询加载状态签名Jyx2:IsLoaded(name)返回布尔值模块name已加载返回true否则返回false。实现即return self[name] ~ nilInitLuaScripts.lua。3.4 直接属性访问 Jyx2.name使用Jyx2.name直接访问模块也是允许的但没有自动加载功能推荐在确认模块已经加载时使用避免访问到nil。3.5 初始化与反初始化钩子除文档列出的三个方法外源码还提供两个生命周期方法值得补充Jyx2:Init()遍历注册表requireList对所有已注册模块执行AddModule实现一次性批量加载InitLuaScripts.lua。脚本文件末尾直接调用了Jyx2:Init()这就是 README 所述LuaManager初始化时自动调用的实际入口。Jyx2:DeInit()逆序遍历moduleList若模块自带DeInit函数则先调用再注销模块并清空列表InitLuaScripts.lua。C# 侧LuaManager.Clear()中通过luaEnv.DoString(if Jyx2 ~ nil then Jyx2:DeInit() end)触发LuaManager.cs这是热重载/场景切换时释放 Lua 资源的统一通道。四、模块注册表 LuaModuleList配置模块与自动加载LuaModuleList是一个以模块名 → 模块主文件路径为映射的 Lua table辅助Jyx2完成模块的定位与加载。当前仓库中的默认注册表内容如下LuaModuleList.lualocal LuaModuleList { ConfigMgr Jyx2Configs/Jyx2ConfigMgr, Battle Jyx2Battle/BattleInit, } return LuaModuleList注册格式统一为moduleName PathOfTheMainFile路径从LuaScripts目录开始且去掉.lua扩展名路径中的目录层级使用/分隔。例如ConfigMgr模块的主文件实际位于Assets/LuaScripts/Jyx2Configs/Jyx2ConfigMgr.lua则注册写为ConfigMgr Jyx2Configs/Jyx2ConfigMgrBattle模块同理对应Assets/LuaScripts/Jyx2Battle/BattleInit.lua注册为Battle Jyx2Battle/BattleInit。从 InitLuaScripts.lua 可以看到注册表通过require LuaModuleList被入口脚本引用而 XLua 的require加载器在 LuaManager.cs 中注册优先从Assets/LuaScripts/{filename}.lua加载找不到则回退到Assets/BuildSource/Lua/{filename}.lua。4.1 注册模块 vs 未注册模块在LuaModuleList中注册的模块可以直接调用Jyx2:GetModule会自动加载且在Jyx2:Init()时被批量加载未注册的模块需先用Jyx2:AddModule(name, path)手动指定路径加载才可调用。五、编写一个自定义 Lua 模块的完整流程结合模块注册表与Jyx2全局表一个可用的 Lua 模块至少包含两个文件。第 1 步编写模块主文件。模块主文件返回一个 Lua table内部可挂载字段与函数。以仓库内置的配置模块 Jyx2ConfigMgr.lua 为范例其骨架是local Jyx2ConfigMgr {} Jyx2ConfigMgr[ConfigList] {} -- 模块内部数据 function Jyx2ConfigMgr:AddConfigTable(cfgName, cfgData) -- 业务逻辑…… end return Jyx2ConfigMgr第 2 步在LuaModuleList中注册例如新增一个MyModulelocal LuaModuleList { ConfigMgr Jyx2Configs/Jyx2ConfigMgr, Battle Jyx2Battle/BattleInit, MyModule MyModule/MyModuleMainFile, -- 新增主文件位于 Assets/LuaScripts/MyModule/MyModuleMainFile.lua } return LuaModuleList第 3 步使用模块。注册后即可通过以下三种方式之一获取模块local mod Jyx2:GetModule(MyModule) -- 自动加载推荐 Jyx2:AddModule(MyModule) -- 手动加载按注册表路径 local m2 Jyx2.MyModule -- 直接访问需确认已加载第 4 步可选实现反初始化。如果模块持有需要释放的资源可在模块 table 上定义DeInit函数它会在Jyx2:DeInit()被调用时自动执行例如 Jyx2ConfigMgr.lua 中的DeInit用于清空所有配置表。六、Mod 中覆盖 Lua 文件以 Mod 逻辑替换框架逻辑这是 LuaScripts 最具实战价值的能力在 Mod 的根目录创建LuaScripts目录并加入 Mod 的 AB 包中即可用 Mod 中的 Lua 文件覆盖游戏框架中对应的 Lua 文件。目录对位规则如下框架内置脚本位于Assets/LuaScripts/其下的子目录结构如Jyx2Configs/在 Mod 中必须原样保留Mod 侧文件路径为Assets/Mods/ModId/LuaScripts/同构子目录/同名文件.lua覆盖生效的前提是Mod 的LuaScripts目录被打入 Mod 的 AB 包且加载时按同名路径命中框架侧脚本。举一个官方文档给出的具体例子若在 Mod 中重载LuaModuleList文件Assets/Mods/MyMod/LuaScripts/LuaModuleList.lua即可自行决定哪些模块自动加载若要自动加载 Mod 新增的模块MyModuleName主文件为Assets/Mods/MyMod/LuaScripts/MyModule/MyModuleMainFile.lua注册写法为MyModuleName MyModule/MyModuleMainFile即去掉LuaScripts以及之前的目录结构只保留LuaScripts之下的相对路径且不带.lua后缀。需要提醒的两点边界覆盖的是同名同路径的脚本因此 Mod 新增模块时路径必须与注册表字符串严格一致从 LuaManager.cs 的require加载器看框架侧查找基准是Assets/LuaScripts/前缀Mod 侧脚本需确保随 AB 包正确打进该命名空间才能在require时命中。七、使用 LuaTestStarter 调试 Lua 脚本LuaTestStarter.asset 是一个 Lua 代码调试器资产ScriptableObject用于在开发阶段快速验证 Lua 脚本逻辑无需启动完整游戏流程。操作步骤来自 README与实现一致在 Project 视图中点击LuaTestStarter.asset在右侧Inspector面板中按顺序将需要运行的 Lua 脚本TextAsset加入luaFiles列表点击测试Lua代码按钮脚本将依次运行。其底层实现位于 LuaTestStarter.cs仅UNITY_EDITOR下生效核心逻辑为LuaManager.Clear(); // 清理旧的 Lua 环境 LuaManager.Init(require main); // 重建 XLua 虚拟机 var luaEnv LuaManager.GetLuaEnv(); foreach (var file in luaFiles) { Debug.Log($开始测试{file.name}); luaEnv.DoString(Encoding.UTF8.GetBytes(file.text), file.name); // 逐个执行 }这说明LuaTestStarter的测试环境是独立于游戏运行时的每次点击都会先Clear再Init因此测试脚本中可以放心使用Jyx2全局表及其模块加载接口。仓库中的 testLua.lua 便是一个可直接加入列表试运行的示例脚本。同时LuaManager.cs 中定义了一个对编辑器开发很实用的开关/// summary /// 是否在editor中调试时热加载lua可以不重启游戏进行编辑 /// /summary public const bool HOTRELOAD_LUA_IN_EDITOR true;开启后默认true编辑器模式下 LoadLua 会直接从Assets/Mods/当前ModId/Lua/目录读取.lua文件省去重新打包 AB 的等待配合LuaTestStarter可形成改脚本 → 点测试的高效迭代闭环。八、源码验证模块注册与加载的完整调用链将上述机制串起来一次典型的模块初始化调用链为LuaManager.Init(...) -- 创建 LuaEnv注册 require 加载器 └─ InitLuaScripts() -- Jyx2ResourceHelper.cs 中调用 └─ require InitLuaScripts.lua -- 定义全局 Jyx2读取 LuaModuleList └─ Jyx2:Init() -- 遍历注册表批量 AddModule └─ require Jyx2Configs/Jyx2ConfigMgr -- 模块主文件返回 table └─ Jyx2.ConfigMgr 模块table -- 注册到全局对应代码锚点入口调用见 Jyx2ResourceHelper.cs全局表定义与初始化见 InitLuaScripts.lua模块注册见 LuaModuleList.lua。已实现的Jyx2Configs模块本身即是最佳参考实现它以Jyx2ConfigMgr为核心提供AddConfigTable配置表载入并自动按Id建索引、GetConfig获取整张表、GetItem(name, id)按 Id 取单条数据、GetLength取表长度与DeInit清空全部配置表等接口Jyx2ConfigMgr.lua并配套ItemHelper.lua、MapHelper.lua提供物品与地图维度的便捷封装。战斗模块则以 BattleInit.lua 为入口通过jy_utils.prequire懒加载DamageCaculator伤害计算、RangeLogic技能范围、AIManagerAI与BattleMgr战斗管理器展示了入口表 子模块预加载的另一种组织风格。九、小结LuaScripts 二次开发速查表需求做法让模块自动加载在LuaModuleList.lua中注册模块名 LuaScripts目录下的相对路径无.lua手动加载模块Jyx2:AddModule(name, path)获取模块带自动加载Jyx2:GetModule(name)判断模块是否已加载Jyx2:IsLoaded(name)直接访问已加载模块Jyx2.模块名在 Mod 中覆盖框架脚本在 Mod 根目录建LuaScripts目录保持相对路径与文件名一致打入 Mod 的 AB 包批量测试 Lua 脚本打开LuaTestStarter.asset将脚本加入列表点击测试Lua代码编辑器热重载 Lua保持HOTRELOAD_LUA_IN_EDITOR true脚本直接从 Mod 的Lua/目录读取后续若有新功能模块需要 Lua 化遵循模块主文件返回 table → 注册到LuaModuleList→ 通过Jyx2访问三步即可无缝接入现有框架。【免费下载链接】jynewJinYongLegend-like RPG Game Framework with full Modding support and 10 hours playable samples of game.项目地址: https://gitcode.com/GitHub_Trending/jy/jynew创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表