|
|
本帖最后由 鼓掌之间 于 2026-6-26 10:35 编辑
转自:https://www.nexusmods.com/subnautica2/mods/20
在《深海迷航2》的设置菜单中添加一个"MOD"标签页,供其他MOD注册各自的设置选项。所有接入本工具的MOD都需要依赖它运行。部分设置可跨会话保存,且能实时生效,无需重新加载存档。安装完成后,任何支持本工具的MOD都会自动在该标签页中显示其配置选项。
安装说明
- 必须先安装《深海迷航2》专用的UE4SS:https://bbs.3dmgame.com/thread-6673249-1-1.html
- 下载最新版本的SN2ModSettings-vX.Y.zip压缩包。使用Vortex(或其他MOD管理器)直接安装即可,压缩包的目录结构已预设为可直接放入UE4SS的MOD文件夹。手动安装时,将文件解压至<深海迷航2安装目录>\Subnautica2\Binaries\Win64\ue4ss\Mods\。无论哪种安装方式,最终MOD文件都应位于ue4ss\Mods\SN2ModSettings\目录下。
- Linux/Proton(应该也包括Steam Deck)用户请参考这篇帖子:https://www.nexusmods.com/subnau ... m&topic_id=16880213
本工具本身不会添加任何可见内容。只有当至少有一个支持本工具的MOD注册了设置后,"MOD"标签页才会显示。
给MOD开发者的说明
如果你的项目使用了本设置工具,请给我发消息,我会在页面底部添加你的链接!
SN2ModSettings会在游戏内设置界面添加一个"MOD"标签页。你的MOD只需在SN2ModSettings/registrations/目录下放置一个Lua清单文件,本库就会使用与原版菜单相同的控件类渲染UI界面。数值使用滑块控件,布尔值使用开关控件,并支持可选的启用依赖控制,让主开关可以灰化其所有子选项。
每个注册的MOD都会在"MOD"标签页中拥有独立的分区,以你设置的显示名称作为分区标题(样式与原版的"显示"、"音频"等标题一致)。MOD按名称字母顺序排列,确保每次启动游戏时顺序稳定。当用户选中某个设置项(鼠标悬停或通过键盘/手柄聚焦)时,描述信息会显示在右侧面板中。
当用户修改设置时,新值会同步到UE4SS的SharedVariable(内存中的跨MOD变量),同时写入SN2ModSettings/saved/<你的MOD名>.lua文件进行持久化。你的MOD可以在一个1秒的异步循环中读取SharedVariable,并实时应用更改。无需重新加载存档,也不需要每帧执行文件I/O操作。
UE4SS为每个LuaMOD提供了独立的隔离全局环境(_G),因此你无法通过全局变量或require语句在MOD间共享表。SharedVariable是UE4SS官方的跨MOD通信通道;而保存文件则作为持久化和调试层。
文件布局
ue4ss/Mods/SN2ModSettings/
├── registrations/
│ └── YourMod.lua <- 你在加载时编写此文件
└── saved/
└── YourMod.lua <- 本库将用户调整后的值写入此处
编写你的清单文件
选择一个简短且稳定的名称。它会同时作为注册文件和保存文件的文件名,因此发布后不要更改,否则会导致用户已保存的设置全部丢失。
local MANIFEST_PATH = "./ue4ss/Mods/SN2ModSettings/registrations/MyMod.lua"
local function write_text(path, body)
local dir = path:match("(.*[/\\])")
os.execute('mkdir "' .. dir:gsub("/", "\\") .. '" 2>nul')
local f = io.open(path, "w")
if not f then return false end
f:write(body)
f:close()
return true
end
local manifest = [=[
return {
name = "MyMod",
display = "我的MOD",
settings = {
{
key="Enabled",
title="启用MOD",
description="总开关。关闭时,下方的滑块将变为灰色不可用状态。",
type="toggle",
default=true
},
{
key="Intensity",
title="强度 (%)",
description="效果强度。100 = 原版效果。",
type="slider",
default=1.0,
min=0.0,
max=2.0,
step=0.1,
format="percent",
enabled_by="Enabled"
},
{
key="FOV",
title="视场角",
description="相机视场角,单位为度。",
type="slider",
default=90.0,
min=60.0,
max=120.0,
step=1.0,
format="integer",
enabled_by="Enabled"
},
},
}
]=]
write_text(MANIFEST_PATH, manifest)
顶级清单键说明
- name:内部ID和保存文件的基础名称。简短、稳定,发布后不要更改。
- display:在"MOD"标签页中显示的分区标题(例如"消耗速率"、"简易制作")。
- settings:设置定义数组。
单个设置项键说明
- key:保存文件中使用的字段标识符。
- title:控件旁边显示的标签。省略时将使用key作为替代。
- description:用户选中设置项时在右侧面板显示的描述。可省略。
- type:控件类型,可选值为"slider"(滑块)或"toggle"(开关)。
- default:滑块的默认数值,开关的默认布尔值。请确保此值与你在Lua代码中的默认值保持一致。
- enabled_by(可选):同一MOD中另一个设置项的key。当该设置项的值为假(开关关闭或数值为0)时,当前控件将变为灰色并停止响应输入。
滑块额外参数
滑块还接受min、max、step和format参数:
- step:数值增量(例如0.1表示保留一位小数)。浮点数/百分比格式默认值为0.1,整数格式默认值为1.0。
- format(可选):滑块数值在轨道旁的显示方式:
- "float"(默认):显示原始小数值。适用于距离、视场角度数、不需要显示为百分比的乘数等。
- "integer":显示四舍五入后的整数。适用于计数和毫秒数。
- "percent":将数值乘以100并添加%后缀。仅当你的滑块在语义上表示百分比时使用(例如1.0代表100%原版效果的乘数)。
最小值和最大值会显示在滑块轨道的两端。
读取保存的值
提供两种读取方式,选择最适合你MOD的一种。两种方式会保持同步。
方式1(推荐):UE4SS SharedVariable,按设置项存储原始值
从v1.0.8版本开始,本库会将每个设置项单独作为原生Lua基本类型进行同步,键格式为"SN2ModSettings/<你的MOD名>/<设置项key>"。无需序列化、无需load()、无需pcall()。只需直接获取值,会返回数字、布尔值或字符串。内存读取几乎没有性能开销,因此即使有数十个MOD同时轮询也不会影响性能。本库会在启动时使用你的默认值初始化所有SharedVariable,因此在用户本次会话中拖动任何滑块之前,第一次读取就会返回有效数据。
local Config = {
Enabled = true, -- 默认值;会被SharedVariable读取结果覆盖
Intensity = 1.0,
}
local function LoadFromShared()
if not ModRef then return false end
local changed = false
for k, _ in pairs(Config) do
local v = ModRef:GetSharedVariable("SN2ModSettings/MyMod/" .. k)
if v ~= nil and type(v) == type(Config[k]) and Config[k] ~= v then
Config[k] = v
changed = true
end
end
return changed
end
LoadFromShared() -- 启动时初始化
LoopAsync(1000, function()
-- 在异步循环线程中进行轻量检查(内存读取不需要游戏线程)
-- 仅当配置实际发生变化时才安排应用操作
if not LoadFromShared() then return end
ExecuteInGameThread(function()
print("[我的MOD] 配置已更改,正在重新应用")
-- 应用 Config.Enabled / Config.Intensity 等设置
end)
end)
方式2(传统):文件轮询
本库仍会在每次设置变更时写入SN2ModSettings/saved/<你的MOD名>.lua文件。如果你希望方便调试(直接打开文件查看)或需要直接访问持久化层,可以使用此方式。每次轮询会产生磁盘I/O操作,以及一次load()/pcall()解析过程:
local Config = {
Enabled = true, -- 必须与清单中的默认值一致
Intensity = 1.0,
}
local function LoadSavedConfig()
local f = io.open("./ue4ss/Mods/SN2ModSettings/saved/MyMod.lua", "r")
if not f then return false end
local content = f:read("*all")
f:close()
if not content or content == "" then return false end
local loader = load(content)
if not loader then return false end
local ok, data = pcall(loader)
if not ok or type(data) ~= "table" then return false end
local changed = false
for k, v in pairs(data) do
if Config[k] ~= nil and type(v) == type(Config[k]) and Config[k] ~= v then
Config[k] = v
changed = true
end
end
return changed
end
LoadSavedConfig() -- 启动时读取已保存的值
LoopAsync(1000, function()
ExecuteInGameThread(function()
if LoadSavedConfig() then
print("[我的MOD] 配置已更改,正在重新应用")
end
end)
end)
支持的控件
目前支持:滑块和开关。计划但尚未实现:下拉框(combobox)、按钮(动作触发器)、单选组(radio)。原版《深海迷航2》的设置使用了所有这些控件,因此底层控件类已经存在。快捷键绑定优先级较低,因为它需要通过EnhancedInput用户设置系统实现,流程更复杂。
注意事项
1. 本库会在启动时使用你的默认值为每个清单设置项初始化SharedVariable,即使用户本次会话中还没有拖动过滑块。因此,你的Lua代码中的Config默认值实际上只在MOD加载到第一次SharedVariable读取之间的短暂窗口内有效。
2. 保存值类型:滑块值返回Lua数字类型,开关返回布尔类型。如果你需要整数滑块,请在你的代码中进行四舍五入。
3. enabled_by仅作用于UI层面。灰化滑块只会阻止用户拖动,但不会改变MOD从磁盘读取的值。如果你的主开关关闭,MOD需要自行控制其行为。《深海迷航2-消耗速率》MOD提供了参考模式:主开关关闭时强制所有乘数为原版1.0;主开关重新打开时从保存的滑块值恢复。
4. 本库会在设置变更的瞬间写入保存文件,但实际应用更改是你MOD的责任。特别是对于GAS属性,你需要使用OnRep_<字段名>聚合器刷新技巧;《深海迷航2-消耗速率》MOD有可工作的参考实现。没有这个技巧,游戏效果捕获会保持陈旧状态,你的更改只有在重新加载存档后才会生效。
5. 发布后不要重命名你的MOD——name是保存文件的键,更改它会导致所有用户的现有设置丢失。
下载地址:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
评分
-
2
查看全部评分
-
|