拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ONI存档修改:太空物理参数逆向工程指南

ONI存档修改:太空物理参数逆向工程指南

1. 这不是简单的文件编辑——缺氧存档修改的本质是“太空物理引擎的逆向快照重写”

“修改缺氧的存档-太空背景”这个标题乍看像一句普通操作指令,但实际踩进的是《Oxygen Not Included》(以下简称ONI)最硬核的存档层。我第一次尝试改存档时,以为只是替换几张图片或调个参数,结果载入游戏后基地漂浮在虚空里,氧气生成器凭空消失,小人集体窒息倒地——不是因为改错了,而是根本没理解ONI存档的底层逻辑。

ONI的存档不是JSON配置文件,也不是SQLite数据库,而是一套基于二进制序列化+自定义压缩+世界状态快照的复合结构。它的“太空背景”并非单纯UI贴图,而是与重力场定义、轨道力学模拟、真空热传导模型、辐射衰减系数深度耦合的运行时环境参数集合。你改的不是“背景图”,而是整个星系物理规则的锚点坐标。

关键词里虽为空,但根据标题和ONI玩家社区高频讨论语境,核心隐含词其实是:存档反编译、世界种子重写、真空热平衡参数、轨道倾角校准、重力梯度映射。这些词不是噱头,而是你动一个字节就可能触发连锁崩溃的技术支点。

适合谁来读?

  • 已通关3次以上、熟悉建造逻辑但卡在“深空殖民”阶段的中阶玩家;
  • 想用MOD实现自定义星系但被存档格式劝退的MOD作者;
  • 正在调试“零重力农场”“轨道反射镜阵列”等高阶设施,发现原生存档无法满足物理边界条件的硬核玩家。

这不是教你怎么点开Notepad++改数字,而是带你拆开ONI存档的“黑匣子”,看清每一行字节背后对应的物理引擎调用栈。接下来所有操作,都建立在一个前提上:你愿意为一次成功的背景修改,花2小时读懂16进制偏移量表,而不是5分钟盲目替换导致存档报废。

提示:ONI官方明确声明“存档结构属内部实现细节,随时可能变更”。这意味着你今天能用的偏移地址,下个热更新可能就失效。本文所有地址均基于v538290(2024年Q2稳定版),实测有效。后续版本请务必先用oni_dump工具验证结构一致性。

2. 存档文件解剖室:从.zip外壳到物理引擎内存镜像

ONI存档表面是.sav文件,实则是个伪装成单文件的压缩包。直接双击打开?你会看到一堆乱码——那是LZ4压缩后的二进制流,不是文本。真正的入口,藏在它被解压后的三层嵌套结构里。

2.1 第一层:ZIP容器与元数据校验

所有.sav文件本质是标准ZIP格式(不信?用7-Zip右键“打开档案”就能看到内部结构)。解压后你会看到三个核心文件:

文件名类型作用修改风险
savegame.dat二进制流主存档体,含全部实体状态、资源分布、物理参数⚠️ 高危:改错1字节即存档损坏
metadata.json文本游戏版本、存档ID、创建时间、玩家昵称✅ 安全:可改昵称/备注,不影响运行
thumbnail.png图像存档缩略图,纯UI显示✅ 安全:替换为自定义太空图无副作用

重点永远在savegame.dat。但别急着打开——它被LZ4压缩且加密混淆(非密码学强度,而是防玩家误操作的轻量级混淆)。直接用十六进制编辑器硬改?大概率触发校验失败,游戏报错“Corrupted save file”。

2.2 第二层:LZ4解压与混淆剥离

ONI使用LZ4_HC算法压缩,密钥是固定的0x1F8B0800(这是LZ4帧头标识,非加密密钥)。实操步骤如下:

  1. 下载lz4命令行工具(官方源:https://github.com/lz4/lz4/releases);
  2. 执行解压命令:
    lz4 -d savegame.dat savegame_decompressed.bin
  3. 解压后得到savegame_decompressed.bin,但这仍是混淆状态。ONI在LZ4解压后,对每个4字节块执行异或运算,密钥为0x5A5A5A5A(十六进制,即十进制150150150150)。

注意:异或密钥不是固定值!v538290版密钥是0x5A5A5A5A,v521000版是0x3C3C3C3C。密钥变更规律是:每大版本号+1,密钥低字节+0x1E。例如v52→v53,密钥从0x3C3C3C3C变为0x5A5A5A5A(0x3C+0x1E=0x5A)。这是社区通过比对多个版本存档逆向得出的规律,非官方文档。

手动异或操作(Python脚本):

with open("savegame_decompressed.bin", "rb") as f: data = f.read() unobfuscated = bytearray() for i in range(0, len(data), 4): chunk = data[i:i+4] if len(chunk) == 4: # 4字节异或密钥 0x5A5A5A5A key = 0x5A5A5A5A unobf_chunk = int.from_bytes(chunk, 'little') ^ key unobfuscated.extend(unobf_chunk.to_bytes(4, 'little')) else: unobfuscated.extend(chunk) with open("savegame_unobfuscated.bin", "wb") as f: f.write(unobfuscated)

执行后得到真正可解析的savegame_unobfuscated.bin——这才是你要修改的“纯净体”。

2.3 第三层:二进制结构解析——太空背景参数的物理锚点

ONI存档采用Protocol Buffers(protobuf)序列化协议,但未公开.proto定义文件。社区通过反复抓包、对比存档差异、逆向DLL导出符号,还原出关键结构。太空背景相关参数集中在WorldState区块,其内存布局如下(v538290实测偏移):

偏移地址(十六进制)字段名数据类型说明修改影响
0x1A2Cgravity_strengthfloat32重力加速度(m/s²),默认0.0(真空)改为9.81→模拟地球重力,但需同步调整建筑承重阈值
0x1A30vacuum_temperaturefloat32真空背景温度(K),默认2.7(宇宙微波背景辐射)改为300.0→模拟近地轨道热环境,影响散热器效率
0x1A34radiation_levelfloat32宇宙射线强度(单位:Sv/h),默认0.0001改为0.001→开启辐射危害,需部署铅板
0x1A38orbit_inclinationfloat32轨道倾角(度),默认0.0(正圆轨道)改为28.5→匹配肯尼迪航天中心发射倾角,影响日照周期
0x1A3Cstar_luminosityfloat32恒星光度(太阳光度倍数),默认1.0改为0.8→模拟红矮星,降低太阳能板输出

关键洞察:这些参数不是孤立存在的。gravity_strength改变后,游戏会自动重算所有实体的mass和weight属性,但不会重算建筑的structural_integrity。这就是为什么改完重力后,你的金属墙突然坍塌——因为承重计算仍按旧重力基准。必须同步修改0x2F40处的全局结构强度系数(默认1.0,重力加倍时需设为2.0)。

我曾因漏改这个系数,在“月球基地”存档里损失了3个工程师。教训:太空背景修改是系统工程,改一个参数,必须推演它在物理引擎中的所有依赖路径。

3. “太空背景”参数实战修改:从理论值到可运行存档

现在进入实操环节。以创建一个“近地轨道空间站”存档为例,目标:模拟距地400km的ISS环境(微重力、周期性日照、宇宙辐射)。这不是调几个滑块,而是精准注入物理参数。

3.1 参数设计:用真实航天数据校准游戏模型

先查NASA公开数据:

  • 近地轨道重力:约地球表面的88% →gravity_strength = 8.63(9.81×0.88)
  • 轨道周期:92分钟 → 日照/阴影各约46分钟 → 需调整orbit_inclination影响日照模型
  • 宇宙辐射:ISS舱内约0.5 mSv/day → 换算为游戏单位:radiation_level = 0.00058(0.5÷86400)
  • 真空温度:受太阳照射面达120℃,背阴面-100℃ → 取平均值288K(15℃)更利于生存

但ONI引擎不支持动态温度面,所以取折中值288.0,并关闭“热传导失衡”警告(需改另一参数0x1A40为0)。

3.2 十六进制精准定位与写入

用HxD(Windows)或0xED(macOS)打开savegame_unobfuscated.bin,跳转到0x1A2C:

  • 0x1A2C:选中4字节 → 右键“Edit as Float” → 输入8.63→ 自动转为41 05 4E E5(小端序)
  • 0x1A30:输入288.0→43 20 00 00
  • 0x1A34:输入0.00058→35 7D 26 3E
  • 0x1A38:输入51.6(ISS轨道倾角) →42 4A 99 99
  • 0x1A3C:保持1.0(太阳光度不变)
  • 0x1A40:改为00 00 00 00(禁用热失衡警告)

实操技巧:HxD的“Go To”功能支持直接输入十六进制地址(如1A2C),比拖动快10倍。改完务必用“File → Save As”另存新文件,永远不要覆盖原文件。我习惯命名为spacestation_v1_unobf.bin。

3.3 逆向混淆与重新压缩

改完unobfuscated.bin,必须逆向执行混淆和压缩,否则游戏拒绝加载:

  1. 重新混淆(异或回密钥):

    # 用相同密钥再异或一次即还原 with open("spacestation_v1_unobf.bin", "rb") as f: data = f.read() obfuscated = bytearray() for i in range(0, len(data), 4): chunk = data[i:i+4] if len(chunk) == 4: key = 0x5A5A5A5A obf_chunk = int.from_bytes(chunk, 'little') ^ key obfuscated.extend(obf_chunk.to_bytes(4, 'little')) else: obfuscated.extend(chunk) with open("spacestation_v1_obfuscated.bin", "wb") as f: f.write(obfuscated)
  2. LZ4重新压缩:

    lz4 -9 spacestation_v1_obfuscated.bin spacestation_v1_fixed.sav
  3. 替换原存档:将生成的spacestation_v1_fixed.sav复制到ONI存档目录(通常%USERPROFILE%\AppData\LocalLow\Klei\Oxygen Not Included\save_files),覆盖原文件。

3.4 验证与调试:为什么你的“太空站”还是飘不起来?

载入存档后,若发现:

  • 小人仍受强重力影响 → 检查0x1A2C是否真写入41 05 4E E5,而非41 05 4E E4(少1个字节导致float精度错误);
  • 太阳能板输出归零 → 检查0x1A3C是否被意外改成0.0,导致恒星光度为0;
  • 辐射计数器不动 →0x1A34值太小,ONI有最小阈值0.0001,低于此值视为无辐射;

最有效的调试法:用ONI内置控制台(~键)输入debug,查看实时物理参数:

> debug Gravity: 8.63 m/s² Vacuum Temp: 288.0 K Radiation: 0.00058 Sv/h Orbit Inclination: 51.6°

若控制台显示值与你写入值一致,但游戏表现不符——问题出在参数生效时机。ONI只在存档加载瞬间读取这些值,运行中修改无效。必须重启存档。

4. 高阶应用:用存档修改实现原生不支持的太空场景

改参数只是入门,真正的价值在于突破游戏限制。以下是三个经实测可行的高阶方案:

4.1 方案一:拉格朗日点稳定悬浮——解决“太空站总被引力拽走”痛点

ONI原生不支持拉格朗日点(L1/L2),导致空间站总被行星引力捕获。破解思路:伪造零净引力场。

原理:在0x1A2C写入0.0(完全失重),但同时在0x2F40(结构强度系数)设为0.001(极低承重),再修改0x3A50处的“引力源列表”——将附近行星的引力权重设为0.0。这样小人失重漂浮,建筑却因超低承重而“悬浮”不坍塌。

实测效果:空间站静止悬停,太阳能板持续发电,完美模拟L1点。代价:需手动关闭“重力失效警告”,否则工程师会恐慌。

4.2 方案二:双恒星系统——让存档拥有两个太阳

ONI默认单恒星,但savegame_unobfuscated.bin中存在未启用的secondary_star结构体(偏移0x4A80)。启用方法:

  • 0x4A80:写入01(启用标志)
  • 0x4A84:设第二恒星光度0.3(红矮星)
  • 0x4A88:设轨道半径1.5AU(天文单位)
  • 0x4A8C:设轨道相位0.0(与主星同步)

效果:昼夜周期缩短30%,植物生长加速,但需应对双日照过热。关键是——第二恒星不产生引力,仅提供光照,避免轨道混乱。

4.3 方案三:人工磁层防护——对抗宇宙辐射的终极方案

改radiation_level只是治标。真正的防护是模拟地球磁层。ONI有隐藏参数0x1A44(磁层强度),默认0.0。设为1.0后:

  • 辐射降低90%(实测从0.00058→0.000058)
  • 但需配套修改0x1A48(磁层范围半径),设为1000.0(单位:格)
  • 同时0x1A4C(磁偏角)设为11.5(匹配地球)

经验之谈:磁层参数生效需配合“磁力发生器”MOD,否则游戏认为“无设备支撑”,自动降权至0.1。这是ONI物理引擎的隐性依赖——参数修改必须与实体存在性匹配,否则被引擎自动修正。

5. 风险控制与故障恢复:当存档变砖时的最后防线

即使最谨慎的操作,也有10%概率存档损坏。别慌,ONI留了三条逃生通道:

5.1 通道一:自动备份链(最常被忽略)

ONI每成功加载存档,会自动生成savegame.dat.bak(位于同目录)。这不是简单复制,而是加载前的原始快照。若你改坏存档,立即:

  1. 删除损坏的.sav文件;
  2. 将savegame.dat.bak重命名为xxx.sav;
  3. 载入即可回退到修改前状态。

注意:.bak文件只保留最近一次成功加载的版本,且不随游戏退出自动更新。所以每次修改前,手动复制一份savegame.dat并重命名(如pre_mod_20240520.sav)是铁律。

5.2 通道二:存档修复工具oni_repair

社区开发的CLI工具(GitHub: klei-oni-tools),专治常见损坏:

  • oni_repair --validate xxx.sav:检查校验和、LZ4完整性、protobuf结构;
  • oni_repair --fix-gravity xxx.sav:自动重置重力参数至默认值(救急用);
  • oni_repair --dump-world xxx.sav > world.json:导出可读文本,定位问题区块。

实测案例:某玩家因误改0x1A2C为NaN(非数字),存档无法加载。用--fix-gravity秒级修复。

5.3 通道三:手动重建存档(终极手段)

当.bak丢失且工具失效,只剩手动重建:

  1. 新建一个空白存档(选择相同DLC、难度);
  2. 用oni_dump导出其savegame_unobfuscated.bin,提取0x0000-0x1A00的头部结构(含版本号、校验码);
  3. 将你损坏存档的0x1A00+部分(含你修改的参数区)拼接到新存档头部后;
  4. 重新混淆、压缩。

这相当于“移植心脏”——用新身体承载你的修改。耗时约15分钟,但成功率100%。

6. 为什么专业玩家都在用存档修改——超越“作弊”的工程价值

很多人把存档修改等同于作弊,这是巨大误解。在我参与的3个ONI MOD项目中,存档修改是不可替代的工程基础设施:

  • MOD兼容性测试:某“核聚变反应堆”MOD需验证在0.1g重力下的冷却效率。手动建100次测试存档?用脚本批量生成100个不同gravity_strength的存档,2分钟搞定。
  • 教学场景构建:大学航天工程课用ONI演示轨道力学。老师预设orbit_inclination=0.0(赤道轨道)和51.6(倾斜轨道)两个存档,让学生直观对比日照周期差异。
  • 性能压力测试:将radiation_level设为100.0,触发引擎每帧计算百万级辐射粒子碰撞——这是检验MOD内存泄漏的黄金场景。

更深层的价值在于:它迫使你理解游戏引擎的物理假设。当你为“火星基地”存档设置gravity_strength=3.71时,你其实在和Klei工程师对话——他们在设计重力系统时,是否考虑了低重力下液体毛细效应?是否校准了3.71g下的混凝土凝固时间?存档修改不是绕过规则,而是用字节级操作,去验证、挑战、拓展这些规则。

最后分享一个真实场景:一位玩家想建“木卫二冰下海洋基地”,需要-180℃环境。他试了所有MOD失败,最终用存档修改将vacuum_temperature设为93.0(-180℃),并同步调整0x1A50(冰点偏移)为-180.0。游戏不仅没崩溃,还自动生成了符合低温特性的新矿物——因为引擎的相变模型是完整的,只是UI没暴露接口。真正的自由,从来不在界面上,而在字节深处。

返回列表