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 渲染方案

以船插为例初步熟悉代码

本章开始涉及代码。编者将以一个提高舰船速度的船插为例,介绍 Java 文件中几个会用到的位置。先创建效果文件,再登记船插,最后修改参数并进入游戏观察结果。和此前的数据制作一样,仍然从复制和修改现成内容开始。

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

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

学习目标

完成后,您将能够:

  • 找出示例 Java 文件中照抄的结构与可以修改的参数;
  • 修改一个速度参数,重启后在装配界面和模拟战中确认效果;
  • 解释数据注册与游戏回调在本例中的作用;
  • 根据文件、数据与日志定位加载失败或修改未生效的问题。

前置知识

  • [C1-S1] 的 MOD 目录、mod_info.json 与 gear_in MOD;
  • [C1-S2] 的舰船获取、装配界面与模拟战操作;
  • [C1-S7] 的 CSV 列边界、行首注释与文本编码。

准备一个加速船插

本例将制作一个名为 "加速器" 的船插,效果是提高舰船最大速度 10%。船插 ID 为 GearIn_speed_booster,效果类名为 GearInSpeedBooster。

在 MOD 根目录下创建 data/scripts/gearin/hullmods/GearInSpeedBooster.java。完整文件见本节的 "完整最小例",下面先解释修改时会涉及的几处内容。

包名、目录与类名

文件开头的包声明如下:

package data.scripts.gearin.hullmods;

类声明位于 import 行之后,局部片段如下:

public class GearInSpeedBooster extends BaseHullMod {
    // 船插参数和效果方法放在这里。
}

package 说明这个类属于哪个包;在当前的源码目录里,点号对应目录层级。沿包名逐级找到 data/scripts/gearin/hullmods/,就是这个文件的保存位置。文件名则与 class 后面的 GearInSpeedBooster 一致。

extends BaseHullMod 表示继承游戏提供的船插基类,它提供了船插效果的标准结构。当前的加速效果也写在这个结构中。import 行引入下面用到的游戏类,本例按完整文件复制。

当前阶段先保持最小改动:包名、类名和方法声明按示例填写,效果参数按需要调整。加载失败时,就能沿刚才的目录、文件名和声明对照原文件定位。

速度参数

结构按示例保存后,在类里面找到这一行:

private static final float SPEED_PERCENT = 10f;

SPEED_PERCENT 保存速度加成百分比,当前数值就是等号后的 10f。数字后的 f 表示 Java 的 float 类型;10f 与 10.0f 表示同一个值,0.5f、3.14f 也按这种方式书写。

把这里的 10f 改成 50f,速度加成就变成 50%。本次修改只替换这个数字,保留行末分号与声明的其他部分。

修改速度与记录回调

效果方法使用上述参数写入速度加成,局部片段如下:

@Override
public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
    stats.getMaxSpeed().modifyPercent(id, SPEED_PERCENT);
    Global.getLogger(GearInSpeedBooster.class).info("GearIn_speed_booster applied");
}

游戏在计算这艘舰船的船插效果时调用这个方法,并把数值对象交给它。第一条语句通过 stats.getMaxSpeed() 取得最大速度,再用 modifyPercent(id, SPEED_PERCENT) 写入加成。刚才修改的数字,就在这里参与计算。

游戏在对应时机调用效果方法,这个过程称为回调。 因此,本例的方法名和参数列表采用船插接口规定的写法;我们要调整的具体效果,写在方法体的大括号内。

第二条语句把 GearIn_speed_booster applied 写入 starsector.log,用于确认回调执行。引号内的字符串决定日志内容,本节保留这个固定搜索词,稍后用它确认游戏确实调用了刚才的方法。

注册船插数据

保存效果文件后,还要让船插数据引用它。打开 MOD 的 data/hullmods/hull_mods.csv,为船插添加数据行。文件不存在时,新建文件并写入表头。

script 列负责把数据行接到 Java 类。 本节填写:

data.scripts.gearin.hullmods.GearInSpeedBooster

这个完整类名由包名与类名组成,正好对应前面检查的两处声明。它必须与文件中的 package 和 class 一致,路径按包名对应,大小写也要一致。

在数据中登记船插 ID 和效果类,这个过程称为注册。 游戏读取数据后,装配界面使用其中的名称、成本与描述,效果计算则调用 script 指向的类。

确认数据行中的关键列

填入这条船插记录时,先确认下面几列,其余值按完整示例保存:

  • id:第 2 列,填写船插 ID GearIn_speed_booster,沿用 [C1-S1] 的数据前缀规则。
  • cost_frigate、cost_dest、cost_cruiser、cost_capital:四种船体等级的装配点消耗,分别填写 3、6、9、12。
  • script:填写效果类的完整名字 data.scripts.gearin.hullmods.GearInSpeedBooster。
  • desc:装配界面显示的文字。本节写 "提高舰船最大速度 10%。"。

四档装配点消耗都要填写

四个 cost_* 字段都需要数字。填 0 表示免费;留空会在加载时产生解析错误。修改数据时同时留意 [C1-S7] 的列边界,空列的逗号仍有作用。

完整最小例

效果类写入 data/scripts/gearin/hullmods/GearInSpeedBooster.java,数据行写入 data/hullmods/hull_mods.csv。CSV 已有表头时,只追加这条船插记录。

完整成品:GearInSpeedBooster
package data.scripts.gearin.hullmods;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.BaseHullMod;
import com.fs.starfarer.api.combat.MutableShipStatsAPI;
import com.fs.starfarer.api.combat.ShipAPI.HullSize;

/** 为舰船提供固定百分比的最大速度加成。 */
public class GearInSpeedBooster extends BaseHullMod {

    /** 最大速度加成百分比。 */
    private static final float SPEED_PERCENT = 10f;

    @Override
    public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
        stats.getMaxSpeed().modifyPercent(id, SPEED_PERCENT);
        Global.getLogger(GearInSpeedBooster.class).info("GearIn_speed_booster applied");
    }
}
name,id,tier,rarity,tech/manufacturer,tags,uiTags,base value,unlocked,hidden,hiddenEverywhere,cost_frigate,cost_dest,cost_cruiser,cost_capital,script,desc,short,sModDesc,sprite
加速器,GearIn_speed_booster,0,,,engines,引擎,1000,TRUE,,,3,6,9,12,data.scripts.gearin.hullmods.GearInSpeedBooster,"提高舰船最大速度 10%。","提高最大速度。",,

修改参数并比较结果

保存这两个文件,重启游戏,在装配界面给 [C1-S2] 的工匠安装 "加速器",先观察 10f 的效果。然后把 Java 文件中的 SPEED_PERCENT 改为 50f,再次保存、重启和观察。

实际加成已经变成 50%,描述仍然写着 10%。 为什么改了数值,文字却没变?desc 是 CSV 中的固定文字,效果类使用的是 Java 参数,两处分别修改。参数调整后也要同步描述;[C2-S2] 会介绍用代码填充描述参数的做法。

选择百分比或固定增量

本例使用 modifyPercent(id, 10f),表示按基础最大速度增加 10%。如果希望直接增加固定速度,可以使用下面这个局部片段:

stats.getMaxSpeed().modifyFlat(id, 50f);

它表示增加 50 单位/秒。百分比加成随基础速度变化,固定增量则直接加上指定数值。同一种速度加成,对不同船体的价值也不同。 例如固定加 50 对慢速主力舰的影响往往比对快速护卫舰更明显,因此选择加成方式时,也要考虑它将用于哪类船体。

验证方案

  1. 保存本节的 Java 文件和 CSV,重启游戏,进入已有生涯的装配界面。
  2. 给工匠安装 "加速器",比较安装前后的最大速度,再进入模拟战观察机动表现。
  3. 查看 Starsector/starsector-core/starsector.log,搜索 GearIn_speed_booster applied。
  4. 将 SPEED_PERCENT 改为 50f,保存并重启,给同一艘舰船安装相同船插,再比较数值与机动表现。
  5. 悬停船插,核对 CSV 描述与当前实际加成。

预期结果:

  • 装配界面出现 "加速器",工匠的装配点消耗为驱逐舰档的 6。
  • 10f 时,最大速度获得基础值 10% 的加成;50f 时,加成变为 50%,模拟战中可观察到变化。
  • CSV 描述仍显示 "提高舰船最大速度 10%。"。
  • 每次测试的效果计算阶段都能在日志中找到 GearIn_speed_booster applied,出现次数以实际日志为准。

故障分析

  • 装配界面找不到加速器:hull_mods.csv 缺少本节数据行,或行首仍带 #,游戏没有读到注册信息。

    • 解决方案:确认文件位于 MOD 根目录下的 data/hullmods/hull_mods.csv,保留表头与唯一的 GearIn_speed_booster 行,保存后重启。
  • 加载时报 Error loading [...]:script、package、文件路径或类名没有指向同一个类。

    • 解决方案:逐段核对 data.scripts.gearin.hullmods.GearInSpeedBooster,确认文件名与类声明一致后重启。
  • Java 加载错误带有行号:分号缺失或括号不配对导致源码解析失败。

    • 解决方案:按日志行号对照完整示例,修正该位置并重启。
  • 参数修改后加成不变:文件尚未保存、编辑了另一份源码,或游戏仍在使用启动时加载的类。

    • 解决方案:确认修改的是当前 MOD 的 GearInSpeedBooster.java,保存后重启,再为测试舰船安装船插。
  • 速度加成生效但搜索不到日志文字:搜索词与代码中的字符串不同,或日志级别过滤了该输出。

    • 解决方案:核对代码中的日志字符串与日志配置,在本次启动记录中搜索 GearIn_speed_booster。
  • 加载时报 JSONException:必填列缺失、四档 cost_* 留空,或 CSV 字段错位。

    • 解决方案:按首行列名恢复列边界,补齐四档数字,以 UTF-8 无 BOM 保存并重启。
  • 加载时报 Duplicate key:同一 CSV 文件中重复登记了相同 ID。

    • 解决方案:为每行保留唯一 ID,保存后重启。

总结

船插由数据行与效果类共同构成。CSV 提供身份、成本和描述,Java 方法写入实际加成;注册把两者联系起来,游戏则在数值计算时调用效果方法。

本节采用固定的百分比加成。下一节会加入按船体等级分档的参数、与参数联动的描述和安装限制,让它成为一个适合实际使用的船插。

建议参考项

  • data/hullmods/hull_mods.csv:船插登记表,id、四档 cost_*、script 与 desc 的写入位置。
  • com.fs.starfarer.api.combat.BaseHullMod:本节效果类使用的船插基类。
  • com.fs.starfarer.api.combat.MutableShipStatsAPI:getMaxSpeed() 提供最大速度修改入口。
  • Starsector/starsector-core/starsector.log:加载错误与效果日志的观察位置。
在 GitHub 上编辑此页
上次更新: 2026/10/14 12:25
贡献者: 1847905557
下一页
制作完整船插