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

补充描述文本

本节为本章已制作的舰船、战机与武器补上描述文本。您将先处理 CSV 的列边界和文本转义,再把描述行登记到对应对象上,在游戏界面中确认它们已经被读取。

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

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

学习目标

  • 正确书写 CSV 的空列、英文逗号、双引号和多行文本;
  • 使用表头、行首注释与 UTF-8 无 BOM 保存描述文件;
  • 根据船体 ID 和武器 ID 注册 SHIP、WEAPON 描述行;
  • 在舰队、装配、货舱和数据库界面验证描述文本。

前置知识

  • [C1-S1] 的 MOD 目录、gear_in 与 GearIn_ 数据前缀;
  • [C1-S2] 的 .ship、ship_data.csv 与 CSV 分隔符;
  • [C1-S3] 的战机船体、装配和联队 ID;
  • [C1-S4] 的相位舰船体 ID;
  • [C1-S5] 的 weapon_data.csv、武器 ID 与控制台获取方法。

保持 CSV 的列边界

CSV 用半角逗号分隔字段,首行的列名决定后面每个字段的含义。descriptions.csv 使用下面的表头:

id,type,text1,text2,text3,text4,text5,notes

每条描述记录必须与这个表头保持相同的列数。两个分隔逗号之间为空时,该列留空;末尾留空的列也必须保留分隔逗号。例如,只有 id、type 和 text1 有内容的局部片段:

GearIn_durin,WEAPON,拥有可怕射速的自动炮,成箱地发射高爆弹药。,,,,,

这里 text2、text3、text4、text5、notes 均为空。判断一条记录有多少列时,要看引号外的分隔符;文本本身也可能包含逗号。

用双引号包住含逗号的字段

字段内含英文逗号时,必须用一对半角直双引号包住整个字段。引号内的逗号属于文本,引号外的逗号才分隔列。守炉人的局部描述片段如下:

GearIn_artizan,SHIP,"对锤头-级驱逐舰进行部件替换的尝试,它搭载了比想象中更高端的武器配备,和一副实验性抵抗力场。",这是一艘驱逐舰。,,,,

text1 中的英文逗号被保留为正文。中文逗号属于普通文本,可以直接书写。

把文本里的双引号写成两个

字段内需要显示一个双引号时,必须把它写成两个连续的双引号 "",并用一对双引号包住整个字段。乌里光束的局部片段可以这样写:

GearIn_uri,WEAPON,"这门武器偶尔也被称为 ""热熔枪""。",,,,,

界面显示的名称两侧各有一个双引号。外层引号负责字段边界,内层的双写引号负责文本字符,它们承担不同职责。

把多行文本放进同一个字段

字段内含换行时,必须用一对双引号包住整个多行字段。工匠的局部片段如下:

GearIn_furnaceman,SHIP,"守炉人-级轻型航母以两座甲板提供持续空中掩护,自身保留可观的结构。

即使略显无趣,但依然可堪一用。",这是一艘中坚航母。,,,,

这段内容仍是一条描述记录。text1 保留换行,界面可将正文分段显示;引号外的换行才结束当前记录。

文本转义必须先于对象检查

含英文逗号、双引号或换行的字段必须按 CSV 规则包络与转义。字段边界写错后,文本可能被截断、进入其他列或造成加载失败;排错时先确认字段边界,再核对对象 ID。

用行首井号写注释

行首第一列的 # 表示整行注释,可以保存说明或暂时停用一条描述。局部片段如下:

# 齿轮工业的武器描述
GearIn_durin,WEAPON,拥有可怕射速的自动炮,成箱地发射高爆弹药。,,,,,

注释行被跳过,后面的武器行正常读取。多行描述字段中的字符属于该字段的文本,整行注释写在描述记录之间。

保存文本编码

文件必须使用 UTF-8 无 BOM,CSV 的包围引号必须使用半角直双引号 "。BOM 会污染首列表头,错误编码会让中文显示异常;弯引号的转换也不能代替正确的字段转义。

编者在编写描述时会统一给正文加上外层引号,再按需要转义其中的引号。文字可以继续改,字段边界先保持清楚。

创建描述文件

在 MOD 内创建 data/strings/descriptions.csv,写入表头。游戏会自动读取这个固定路径,合并描述数据,再按 id 与 type 查询文本。

id 与 type 共同确定一条描述。两列必须有内容,type 必须逐字符匹配类型名,大小写属于名称的一部分;空键行会被跳过,非法类型会中止加载。

同一文件中的 id + type 必须唯一,重复组合会造成加载失败。MOD 自有描述必须使用自己的对象键,严禁重复登记原版或其他 MOD 已有的同键描述。

描述缺失可能只显示占位文本

对象已有数据而描述行缺失时,界面可能显示 No description... yet。加载成功只说明文件可以读取;确认描述属于哪个对象,还要检查 id、type 和实际显示位置。

为已有对象登记描述

舰船和战机都使用 SHIP。本章的基础船体使用 .ship 中的 hullId 作为描述键,武器使用 weapon_data.csv 的 id 并填写 WEAPON。

战机联队通过装配找到战机船体,再读取船体描述。[C1-S3] 的炉渣联队 GearIn_slag_wing 使用 GearIn_slag_normal 装配,该装配的 hullId 为 GearIn_slag,因此描述行的 id 必须填写 GearIn_slag。

既有对象描述注册速查表

对象描述行的 idtypeID 来源
工匠-级驱逐舰GearIn_artizanSHIP[C1-S2] 的船体
守炉人-级轻型航母GearIn_furnacemanSHIP[C1-S3] 的船体
炉渣-级战机GearIn_slagSHIP[C1-S3] 的战机船体
锻件-级相位护卫舰GearIn_forgingSHIP[C1-S4] 的船体
都林自动炮GearIn_durinWEAPON[C1-S5] 的武器
乌里光束GearIn_uriWEAPON[C1-S5] 的武器
德瓦林发射架GearIn_dwalinWEAPON[C1-S5] 的武器

text1 保存详细描述,舰船可以用 text2 写一句简略引言。本节的船体说明同时填写这两列,武器说明填写 text1,其余文本列保持空值。

舰船引言在 text2 有内容且 text3 为空时使用 text2;数据库详情读取 text1,战机详情读取对应船体的 text1。文本列的完整用途和描述键扩展由 [C3-S5] 讲解。

描述在界面中的显示位置

在武器 tooltip 中,观察详细说明与数据面板的相对位置:

武器描述在界面中的显示位置

数据面板上方的段落是详细说明,面板中的定位文字与数值来自武器数据。确认注册结果时,用您写入的正文核对说明区域。

在舰船详情中,观察船体标题下方的正文:

舰船描述在界面中的显示位置

船体详情读取详细描述,舰队悬停引言则按文本列选择简略说明。观察两处内容可以分别确认 text1 和 text2。

完整最小例

将以下内容写入 gear_in 的 data/strings/descriptions.csv。文本和上述示例并不完全相同,因为上述示例虽然能够一定程度上讲清机制,但作为文本而言并不怎么能看:

id,type,text1,text2,text3,text4,text5,notes
GearIn_durin,WEAPON,"都林自动炮是一门口径小、射速极快的近距实弹炮。密集的破片在短距离内对护盾有不错的压制效果,但离开射程就毫无用处。",,,,,
GearIn_uri,WEAPON,"乌里光束在中距离持续照射目标,产生稳定的能量伤害与幅能负担。光束本身没有击退力,需要持续瞄准。",,,,,
GearIn_dwalin,WEAPON,"德瓦林发射架向远距离目标倾泻高爆火箭。备弹有限,装填缓慢,但每一发都对装甲构成实质威胁。",,,,,
GearIn_artizan,SHIP,"工匠-级是一艘以导弹见长的驱逐舰。它把锤头-级的中实弹槽位换成了中通用,可以安装强力的导弹武器。",这是一艘中坚驱逐舰,,,,
GearIn_furnaceman,SHIP,"守炉人-级轻型航母以两座甲板提供持续空中掩护, 自身保留可观的结构。",这是一艘轻型航母,,,,
GearIn_slag,SHIP,"炉渣-级是一款廉价的重型战机,装备双管轻型自动炮。",这是一种重型战机,,,,
GearIn_forging,SHIP,"锻件-级相位护卫舰围绕一门中型实弹槽位设计,用相位机动躲避火力。",这是一艘相位护卫舰,,,,

验证方案

前置数据:已启用 Console Commands,并完成 [C1-S2] 至 [C1-S6] 的船体、联队、武器和内置配置。

  1. 保存描述文件并启动游戏,在 starsector.log 中查找 Loading descriptions,确认描述文件加载阶段完成。
  2. 打开生涯控制台,分别执行 Addship GearIn_artizan、Addship GearIn_furnaceman、Addship GearIn_forging 和 Addwing GearIn_slag_wing。
  3. 执行 Addweapon GearIn_durin、Addweapon GearIn_uri、Addweapon GearIn_dwalin,在货舱中逐个悬停武器,核对详细描述。
  4. 在舰队界面依次悬停工匠、守炉人和锻件,核对简略引言。
  5. 进入守炉人的装配界面,悬停炉渣联队,核对显示的是炉渣船体的描述。
  6. 打开数据库 (codex),分别查看工匠、守炉人、锻件、炉渣及三门武器的详情,核对 text1。
  7. 给工匠的 text1 加入一段文字并保存,重启后打开工匠详情,核对新增段落。

预期结果:

  • 描述文件加载完成,日志中本节对象的描述数据没有解析异常;
  • 货舱中的三门武器显示各自 WEAPON 行的正文;
  • 工匠、守炉人和锻件的舰队引言显示各自 text2;
  • 炉渣联队读取 GearIn_slag,SHIP 的正文;
  • 数据库各对象详情显示与其描述行一致的 text1;
  • 保存并重启后,工匠详情显示新增段落。

故障分析

  • 加载时报 Mismatched quotes in the string; last quote: [...]:字段包围引号或内部双引号转义不完整。

    • 解决方案:用一对直双引号包住整个字段,字段内的每个双引号写成 "",保存后重启。
  • 文本截断或进入其他列:英文逗号或多行文本改变了字段边界。

    • 解决方案:为整个字段补齐包围引号,使记录与表头列数一致。
  • 加载时报 Key [type] has invalid value [...]:类型名称的拼写、大小写或首尾空格与枚举名不一致。

    • 解决方案:舰船和战机填写 SHIP,武器填写 WEAPON,保存后重启。
  • 加载时报 Duplicate key [...] while loading [data/strings/descriptions.csv ...]:同一文件中重复登记了相同的 id + type。

    • 解决方案:每个对象与类型组合只保留一条描述记录,保存后重启。
  • 加载时报 JSONObject["id"] not found:BOM 或错误表头改变了首列名称。

    • 解决方案:恢复标准表头并以 UTF-8 无 BOM 保存,重启。
  • 对象显示 No description... yet 或其他对象的文字:描述键、类型或 text1 与目标对象不对应。

    • 解决方案:从船体的 hullId 或武器数据的 id 开始,核对描述行的 id、type 与正文。
  • 舰船引言显示长描述的第一段:text2 为空,或 text3 已有内容。

    • 解决方案:把简略引言写入 text2,并保持本节船体行的 text3 为空。
  • 修改描述后显示内容保持原样:游戏仍使用启动时加载的文本,或当前查看的对象使用其他描述键。

    • 解决方案:保存并重启,再核对该对象实际使用的描述行。

总结

CSV 的表头与分隔符确定列,包围引号保护文本里的逗号和换行,双写引号保留正文中的引号。描述注册把对象 ID、类型和文本放在同一条记录中,界面再按对象读取它。

本章的舰船与战机使用船体 ID 的 SHIP 行,武器使用武器 ID 的 WEAPON 行。文件能够加载之后,还要亲自打开每个对象的详情;有文字出现和出现您刚写的文字,是两件值得分别确认的事。

建议参考项

  • data/strings/descriptions.csv:对象描述的固定注册路径和标准表头;
  • data/hulls/ship_data.csv:舰船与战机船体 ID;
  • data/hulls/wing_data.csv:战机联队与装配的对应关系;
  • data/weapons/weapon_data.csv:武器 ID。
在 GitHub 上编辑此页
上次更新: 2026/10/21 16:20
贡献者: 1847905557
上一页
为舰船加入内置武器、船插与战机