(修复 9.0) 爵士核弹模组支持 API

(修复 9.0) 爵士核弹模组支持 API

修复了多年来积累的底层错误,包括但不限于“未注册菜单”错误。使用相同的依赖ID,因此可以无缝替换原始的Sir Nukes Mod支持API。

未注册菜单的错误已修复!!!

Sir Nukes/Chem O Dun,你们可以自由使用此内容来更新 Mod Support APIs,一旦 Mod Support APIs 更新,我将毫无异议地下架此内容

X4 Mod Support APIs

这是一系列为以多种方式简化模组创建而开发的 API。组件包括:

  • Lua 加载器 API
    • 支持加载 lua 文件
    • 注意:自 X4 7.5 起已非必需,但为向后兼容旧模组而保留。
  • 简易菜单 API
    • 创建自定义菜单
  • 交互菜单 API
    • 添加新的上下文菜单命令
  • 命名管道 API
    • 进程间双向通信
    • 为 Windows 操作系统构建
    • 需要禁用受保护的 UI 模式
  • 热键 API(使用管道)
    • 创建新的热键
  • 时间 API(使用管道)
    • 实时延迟

主要开发在 github 上进行: https://github.com/bvbohnen/x4-projects/tree/master/extensions/sn_mod_support_apis

API 使用的扩展文档: https://github.com/bvbohnen/x4-projects/tree/master/extensions/sn_mod_support_apis/documentation

最新版本(nexus 获取更新可能较慢): https://github.com/bvbohnen/x4-projects/releases

也可在 steam 创意工坊获取。

使用方法: 此模组包含两部分:

  1. X4 扩展包含其他模组可以调用的所有 x4 插件,是任何依赖项所必需的。

  2. 一个可选的外部程序充当命名管道 API 的宿主,并支持热键 API。目前仅限 Windows,需要在 X4 打开时在后台运行,以支持任何热键模组(或其他使用命名管道的模组)。安装了 Python 的用户也可以从 github 获取 Python 源代码版本并直接运行。有关从源代码运行的版本和包要求,请参阅 github 文档。

已修复的错误:

  • 存档加载选项菜单消失:简易菜单 API。
    • 原因: 在会话中途加载已保存的游戏会导致所有已注册的模组选项子菜单从游戏内扩展菜单中永久消失,因为注册提示只在引擎初始启动时触发。(未注册菜单的错误!!!
    • 修复: 我们在 Reset_On_Lua_Reload 中添加了 <event_game_loaded/><event_game_started/> 触发器,并配合防御性的黑板清理,使菜单在每次加载存档时都能干净地重新注册。
  • 重新加载时子菜单 ID 冲突崩溃(简易菜单 API)(同样是未注册菜单的错误
    • 原因: 当模组在重新加载后重新注册其选项菜单时,menu.Register_Options_Menu 会抛出致命的 Lua 异常("Submenu id conflicts with prior registered id"),导致菜单生成崩溃。
    • 修复: 我们将硬错误替换为幂等的表更新(custom_menu_specs[args.id] = args),允许模组安全地更新其菜单而不会使游戏崩溃。
  • ipairs(nil) 致命命令循环崩溃(简易菜单 API)(同样是未注册菜单的错误!!!!
    • 原因: 如果玩家的 $simple_menu_args 黑板为空或返回 nil,用 ipairs 迭代它会抛出 bad argument #1 to 'ipairs' (table expected, got nil),永久冻结简易菜单命令处理。
    • 修复: 添加了防御性的 type(args_list) == "table" 检查,并将参数获取包装在 pcall 中,使命令队列在为空时能够优雅恢复。
  • 无效的 64 位 UniverseID 类型不匹配(ui/userdata/interface.lua 和 ui/simple_menu/interface.lua)
    • 原因: 过早查询 C.GetPlayerID() 或在未剥离 ULL 后缀的情况下对其索引会创建格式错误的 ID,导致黑板操作失败或抛出引擎类型不匹配错误。
    • 修复: 实现了带有 pcall 零值/nil 保护的 GetLivePlayerID(),以及转换前的 ULL 字符串剥离,确保每一帧都能有效访问玩家组件。
  • 用户数据 nil 键和缺失黑板崩溃(ui/userdata/interface.lua 和 md/userdata.xml)
    • 原因: 以 nil 所有者调用用户数据 API,或在玩家的 $__MOD_USERDATA 表创建之前调用,会在任务导演器中产生 Property lookup failed 错误,并导致 Lua nil 索引崩溃。
    • 修复: 我们在 Lua 中添加了空所有者验证保护及错误日志记录,并在 MD 中添加了存在性检查(not player.entity.$__MOD_USERDATA? 及自动初始化)。
  • 未处理的 Lua Require 加载级联(Lua 加载器)
    • 原因: 如果任何模组通过 on_Load_Lua_File 请求了缺失或损坏的 Lua 文件,原始的 require() 会抛出未处理的错误,突然中止所有后续模组的加载流程。
    • 修复: 我们将 require(file_path) 包装在 pcall 中,记录描述性的调试错误并分发失败事件,同时允许所有其他模组不受干扰地加载。
  • 一次性初始化重复执行泄漏(Lua 加载器)
    • 原因: 在 UI 重新加载期间,已注册的初始化函数仍留在全局列表中,导致 UI monkeypatch 和事件监听器递归包装自身并泄漏内存。
    • 修复: 在注册时对模块初始化进行去重,并在首次执行后立即清空 module_inits = {},使 monkeypatch 永远不会被重复应用。
  • 未受保护的自定义菜单构建器崩溃(简易菜单 API)
    • 原因: 如果单个模组在构建其选项子菜单时抛出 Lua 错误,未捕获的异常会使 Egosoft 的整个选项菜单崩溃,并将玩家锁在游戏设置之外。
    • 修复: 将对 menu.Display_Extension_Optionsmenu.Display_Custom_Menu 的调用包装在带有 DebugError 日志记录的 pcall 中,将有问题的子菜单隔离,避免破坏主菜单。
  • 独立菜单窗口高度溢出(简易菜单 API)
    • 原因: 独立菜单在设置框架高度时未考虑标题表的垂直偏移,导致菜单内容和按钮被裁剪到窗口底部边框之外。
    • 修复: 我们更新了高度计算,减去 menu_data.ftable.properties.y,确保所有行和按钮都保持在框架窗口内。
  • 原生 Winpipe DLL 加载失败(ui/c_library/winpipe.lua)
    • 原因: 重命名模组目录或在 UI 安全模式下启动会导致 package.loadlib 在定位 ui_c_library_winpipe_64.txt 时静默失败,从而在无任何解释的情况下禁用原生 Windows 命名管道。
    • 修复: 添加了双重回退路径搜索,检查两个文件夹名称,将执行包装在 pcall 中,并在 UI 安全模式激活时干净地跳过加载。
  • 命名管道命令异常中止(ui/named_pipes/interface.lua)
    • 原因: 接收格式错误的参数或无法识别的管道命令会在 Process_Command 中抛出未捕获的错误,阻止任何后续管道读取或写入的处理。
    • 修复: 我们将 Process_Command 包装在 pcall 中,添加了 nil 参数验证,并为无法识别的命令引入了回退日志记录,以保持管道调度器存活。
  • 过时的目录文件遮蔽(ext_01.cat / ext_01.dat)(同样是未注册菜单的错误,这一个才是大问题!!!!
    • 原因: 预编译的 2019 年目录文件遮蔽了模组的松散脚本,阻止任何错误修复、现代 Lua 改进或 XML 更新在游戏引擎中生效。
    • 修复: 我们永久删除了旧版目录归档,使 Egosoft 的虚拟文件系统直接加载加固后的松散文件。