Starsector Nihilism Guidance
首页
GitHub 项目
首页
GitHub 项目
  • 首页
  • 基础及舰船相关
    • MOD 骨架和入口文件
    • 制作一艘基本舰船
    • 制作一艘航母与战机
    • 制作一艘相位舰
    • 制作火炮、光束与导弹
    • 为舰船加入内置武器、船插与战机
    • 补充描述文本
  • 无需入门的代码修改
    • 以船插为例初步熟悉代码
    • 制作完整船插
    • 制作最小战术系统
    • 为武器加入命中与光束特效
  • 势力与生涯星系
    • 注册一个势力
    • 配置势力舰队
    • 制作 MOD 入口类的最基础适配
    • 制作一个生涯星系
    • 补完描述文本
  • 战役与无代码对象
    • 制作测试战役装配
    • 为模拟战与标题画面加入装配
    • 为舰船加入外观风格
    • 制作一艘模块船
    • 制作一种星体类型
    • 制作一个自定义实体
  • 音频资源与播放
    • 准备 OGG 音频资源
    • 注册音频资源
    • 为游戏对象加入音频
  • Java 工程化
    • 确认 Java 与编译依赖
    • 迁移代码文件到 src
    • 配置 Gradle 工程
    • 构建 JAR 并声明产物
  • 全局服务
    • 制作 MOD 入口类
    • 使用 Global 访问游戏服务
    • 读取设置
    • 调用声音播放器
    • 记录和定位 MOD 日志
  • 战斗运行时
    • 读取战斗引擎状态
    • 读取战斗对象
    • 制作每帧战斗插件
    • 修改舰船数值
    • 配置武器脚本
    • 配置战斗监听器
    • 制作分层渲染插件
  • 战斗内容扩展
    • 详解舰船插件
    • 详解战术系统
    • 详解武器动画
  • 生涯世界与基础服务
    • 读取生涯世界状态
    • 构建生涯地点
    • 配置生涯势力
    • 放置生涯实体
  • 生涯舰队与舰队成员
    • 生成生涯舰队
    • 管理舰队中的成员
    • 舰队状态的重算过程
    • 维护舰队成员状态
    • 读取并修改舰船装配
  • 市场与商品
    • 创建生涯市场
    • 读写货舱内容
    • 注册市场商品
    • 实现专用子市场
    • 制作专用产业
    • 注册特殊物品
    • 实现市场条件
  • 人物与技能
    • 配置人物基础
    • 让人物承担角色
    • 制作角色技能
  • 生涯脚本与情报事件
    • 编写生涯逐帧脚本
    • 监听生涯事件
    • 选择生涯插件
    • 管理舰队活动情报
  • 酒吧事件与任务
    • 组织生涯交互对话
    • 实现对话插件
    • 接入酒吧事件
    • 构建阶段任务
    • 接入酒吧任务
  • Rules 系统、命令与内存
    • 组织 Rules 规则表
    • 编排 Rules 对话
    • 接入 Rules 生涯场景
    • 编写 Rules 命令
    • 使用 MemoryAPI 保存状态
  • 文件读取与写入
    • 读取 MOD 内文本
    • 读取 MOD 内 JSON 文件
    • 读取 MOD 内 CSV
    • 读写 common 数据
    • 实现本地化机制
  • 常用依赖库
    • 接入常用依赖库
    • 使用 LazyLib 几何工具
    • 使用 LazyLib 查询战场
    • 使用 LazyLib 保存公共 JSON
    • 注册 GraphicsLib 光照数据
    • 创建 GraphicsLib 动态光源
    • 制作 GraphicsLib 纹理映射
    • 配置 MagicLib 自动尾迹
    • 创建 MagicLib 运行时尾迹
    • 配置 MagicLib 数据赏金
    • 使用 MagicLib 辅助生涯开发
    • 使用 MagicLib 战斗小工具
  • 可选依赖与 Nexerelin
    • 接入可选依赖
    • 登记 Nexerelin 势力与外交配置
    • 配置 Nexerelin 的两种星区开局
    • 配置 Nexerelin 战略 AI 与扩张规模
    • 登记 Nexerelin 地面战单位与产业
    • 为 Nexerelin 特遣队添加命名与事件响应
    • 制作即时生效的 LunaLib 设置面板
  • 着色器与渲染
    • 使用 Java OpenGL
    • 使用 GLSL 进阶
    • 使用 VBO 和 VAO 保存顶点
    • 使用 SSBO 传递参数
    • 使用实例化进行绘制
    • 选择 BoxUtil 渲染方案

读取设置

将参数放入 settings.json,便能在不修改 Java 源码的情况下调整功能配置。本节写入自有设置键,在应用加载时读取字符串、数值、开关与颜色,再通过一次音量修改解释设置缓存。文件中的值、内存对象与 getter 的结果将在这个实验中分别呈现。

本节预期阅读时间:~15 分钟。

本节预期操作时间:~25 分钟。

学习目标

完成后,您将能够:

  • 使用合并后的 settings 对象;
  • 按键与类型读取自有配置;
  • 区分整数截断、缺省值和缺键异常;
  • 观察并刷新数值缓存;
  • 区分内存设置与跨启动持久化。

前置知识

  • [C6-S4] 的构建与加载;
  • [C7-S1] 的应用加载回调;
  • [C7-S2] 的 Global 设置服务;
  • [C1-S1] 的同路径合并;
  • Java 方法、JSON 对象与异常。

写入功能配置

打开 MOD 的 data/config/settings.json,保留已有的 plugins 等内容,加入下面的自有键:

{
    "GearIn_loop_volume": 0.8,
    "GearIn_service_name": "齿轮工业服务",
    "GearIn_feature_enabled": true,
    "GearIn_example_count": 3.75,
    "GearIn_accent_color": [180, 120, 60, 255]
}

这些键采用 GearIn_ 前缀,合并时与原版和其他功能区分。游戏将同路径配置按对象键合并,Java 代码随后通过 Global.getSettings() 读取结果。本例中的音量、名称和开关都由功能代码使用。

启动器的窗口、开发模式与进程配置有各自的读取入口。即使把同名键写进 MOD 的文件,也要确认使用方确实从游戏设置服务读取它。这里配置的是我们自己的功能参数。

在应用加载时取得参数

在 GearInModPlugin.onApplicationLoad() 中取得设置服务,按配置值的类型选择 getter。音量读为 float,名称读为字符串,开关读为布尔值:

com.fs.starfarer.api.SettingsAPI settings = Global.getSettings();
float volume = settings.getFloat("GearIn_loop_volume");
String serviceName = settings.getString("GearIn_service_name");
boolean enabled = settings.optBoolean("GearIn_feature_enabled", false);

按本例配置,结果是 0.8、齿轮工业服务 与 true。getFloat 和 getString 要求存在能按对应类型读取的值;可选开关使用 optBoolean,没有有效布尔值时采用给定的 false。

必填值缺失时暴露配置错误,可选值缺失时采用默认行为。 选择 getter 时就确定了这个区别。把音量这样的必填参数也一律读成默认值,会掩盖键名或合并问题,功能却仍可能带着错误参数运行。

设置读取方法速查表

方法当前用途与异常/缺省
getString字符串,缺失或无法按要求读取时抛 RuntimeException
getFloat浮点数,缺失或转换失败时抛 RuntimeException
getInt按浮点读取再截断,3.75 返回 3
getBoolean布尔值,缺失或转换失败时抛 RuntimeException
optBoolean读取不到有效布尔时采用给定缺省值
getColorRGBA,缺键采用并缓存 Color.white,格式错误产生异常
getSettingsJSON当前合并对象,供直接查询与修改

完整方法还读取 GearIn_example_count 与 GearIn_accent_color。getInt 将 3.75 截断为 3;需要保留小数时使用 getFloat,需要四舍五入时另行处理。颜色使用四项 RGBA,格式错误会产生异常,缺键则采用并缓存 Color.white。

修改了设置,为什么仍读到旧值

getSettingsJSON() 返回当前合并后的内存对象,可以直接修改其中的键。然而 getFloat、getBoolean 与 getInt 使用进程缓存,再次读取时未必立即使用刚写入的值。

用音量做一次局部实验:保存原值,将内存对象中的音量改为 0.25,读取一次,再调用 resetCached() 并重新读取。最后恢复原值与缓存:

org.json.JSONObject json = settings.getSettingsJSON();
float original = settings.getFloat("GearIn_loop_volume");
json.put("GearIn_loop_volume", 0.25f);
float cached = settings.getFloat("GearIn_loop_volume");
settings.resetCached();
float refreshed = settings.getFloat("GearIn_loop_volume");
json.put("GearIn_loop_volume", original);
settings.resetCached();

原音量为 0.8。JSON 对象改为 0.25 后,第一次 getter 仍读到缓存中的 0.8;刷新后才得到 0.25。恢复对象并再次刷新,结果回到 0.8。内存对象已经改变与 getter 已经采用新值,是两个不同的时机。

颜色缓存的刷新范围

getColor 使用独立缓存,resetCached() 不会清除它。上面的音量刷新流程不能直接用于颜色,颜色需要随设置重载刷新。

setFloat 与 setBoolean 同样修改运行中的设置。它们也不会将结果写回 MOD 的资源文件;重启之后,文件仍提供原来的配置。

固定参数保存到配置文件,需要随对象延续的运行状态则由对应对象保存。跨启动公共数据使用 [C17-S4] 的 common 入口。这里的缓存实验只修改当前进程中的设置,结束后恢复原值。

汇总读取与缓存实验

将下面的局部方法加入 GearInModPlugin,在 onApplicationLoad() 调用 logSettings()。它在同一次应用加载中记录参数与缓存结果,结束前恢复音量:

private void logSettings() throws org.json.JSONException {
    com.fs.starfarer.api.SettingsAPI settings = Global.getSettings();
    float volume = settings.getFloat("GearIn_loop_volume");
    String serviceName = settings.getString("GearIn_service_name");
    boolean enabled = settings.optBoolean("GearIn_feature_enabled", false);
    int count = settings.getInt("GearIn_example_count");
    java.awt.Color color = settings.getColor("GearIn_accent_color");
    org.json.JSONObject json = settings.getSettingsJSON();

    json.put("GearIn_loop_volume", 0.25f);
    float cached = settings.getFloat("GearIn_loop_volume");
    settings.resetCached();
    float refreshed = settings.getFloat("GearIn_loop_volume");
    json.put("GearIn_loop_volume", volume);
    settings.resetCached();

    Global.getLogger(GearInModPlugin.class).info(
            "GearIn settings: name=" + serviceName + ", volume=" + volume
            + ", enabled=" + enabled + ", count=" + count + ", color=" + color
            + ", cached=" + cached + ", refreshed=" + refreshed);
}

方法保留 JSONException 声明,调用它的 onApplicationLoad() 沿用接口允许的 throws Exception。日志器来自入口类,输出中的 volume 是原音量,cached 是修改后尚未刷新的结果,refreshed 是刷新后的结果。整数、颜色与开关也保留在同一条记录中。

验证方案

  1. 保存自有设置键和读取方法,构建 JAR,重启游戏。
  2. 搜索 GearIn settings,核对名称、音量、开关、整数和颜色。
  3. 比较 cached 与 refreshed,再读取原键确认恢复值。
  4. 将 feature_enabled 暂时省略,保存并重启,比较 optBoolean 的 false 缺省。
  5. 恢复当前功能开关,核对 MOD 资源文件保持手动保存的内容。

预期结果:

  • 默认名称与音量为齿轮工业服务和 0.8,开关为 true。
  • example_count 截断为 3,颜色读取当前 RGBA。
  • 缓存实验为 cached0.8、refreshed0.25,恢复后音量 0.8。
  • 省略可选开关时返回 false,读取按给定缺省进行。
  • 方法记录运行结果,内存设置修改按进程范围生效。

故障分析

  • 严格读取抛 RuntimeException:键未合入或值不能按所需类型读取。

    • 解决方案:核对自有键、JSON 值与 getter,保存并重启。
  • 整数读取丢失小数:getInt 采用截断。

    • 解决方案:需要小数时使用 getFloat。
  • 对象修改后读取旧值:对应 getter 缓存尚未刷新。

    • 解决方案:对数值与布尔使用 resetCached,颜色通过设置重载核对。
  • 重启后内存设置恢复文件值:修改只作用于运行对象。

    • 解决方案:固定配置保存到资源,需要跨启动运行数据时使用 common。
  • 启动器配置未按 MOD 键变化:实际读取位置属于启动器或进程参数。

    • 解决方案:按该参数的实际入口设置,功能参数使用独立自有键。

总结

配置按键合并后,由功能代码使用类型 getter 取得。必填参数、可选开关、整数与颜色各有读取方式,选择方法也就选择了缺失或错误值怎样表现。

音量实验还说明了文件、内存对象与缓存的关系:修改运行对象后要处理对应缓存,跨启动保留结果则需要真正的写入入口。一次 getter 返回旧值,原因并不总在配置文件里。

建议参考项

  • com.fs.starfarer.api.SettingsAPI:类型 getter、getSettingsJSON、setFloat、setBoolean 和 resetCached。
  • data/config/settings.json:自有键和对象合并输入。
在 GitHub 上编辑此页
上次更新: 2026/10/14 12:25
贡献者: 1847905557
上一页
使用 Global 访问游戏服务
下一页
调用声音播放器