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

制作 GraphicsLib 纹理映射

material 与 normal 为光照提供表面颜色和方向,工匠级的装甲起伏由此能够随光源位置变化。本节以原始舰船贴图为基准制作两张附加纹理,用 texture CSV 连接船体,再说明查询、自动生成和预载怎样取得这些资源。

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

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

学习目标

完成后,您将能够:

  • 区分原始 Sprite 贴图、material、normal 与 surface 贴图的职责;
  • 在 onApplicationLoad() 中登记 texture CSV 并选择覆盖策略;
  • 制作与舰船 Sprite 贴图画布、位置、透明区和朝向一致的 material/normal 贴图;
  • 用 texture CSV 的 6 个字段把两张贴图登记给 GearIn_artizan;
  • 按对象 ID、类型、纹理类型和动画帧查询 TextureEntry;
  • 在显式 normal 缺失时使用自动生成,并判断缓存与预载状态。

前置知识

  • [C1-S2] 已完成 GearIn_artizan 的舰船 Sprite 贴图与船体登记;
  • [C18-S5] 已在 onApplicationLoad() 中初始化 GraphicsLib 并完成 shader/buffer 能力判断;
  • [C18-S6] 已建立能够照亮舰船表面的动态点光源;
  • 能够使用图像编辑器保存带透明通道的 PNG,并读取 starsector.log。

以原始贴图确定坐标基准

graphics/ships/GearIn_artizan.png 是游戏直接绘制的舰船 Sprite 贴图,也是三类附加纹理的坐标基准。GraphicsLib 在相同像素位置采样附加贴图,因此舰首、舰尾、装甲板和透明区都要与原始 Sprite 贴图重合。

material 贴图提供光照计算使用的表面颜色与反射差异。normal 贴图保存每个像素朝向哪个方向,让位于舰船左侧、右侧或上方的光源照出不同明暗。surface 贴图进一步控制镜面高光的强度和硬度;缺少它时,material 与 normal 仍然可以参与光照,只是没有该船专用的 surface 变化。

**三类附加纹理在原始贴图的同一像素位置采样。**本节先制作 material 与 normal,再按美术需要决定是否加 surface。每类图表达的信息各有用途,画布和船体位置则一起保持一致。

制作同坐标的附加纹理

保留 material 的受光颜色

先复制原始舰船 Sprite 贴图,保留画布尺寸与透明通道,再把副本改成 material 贴图。处理时以 "光照下希望保留什么颜色、哪些区域更容易反光" 为判断标准:装甲主体保留可辨认的色相,金属边缘和高光区域可以更亮,孔洞与完全透明区域保持透明。

material 贴图仍是一张完整的 RGBA PNG。它不负责画出光源本身,也不替代原始舰船 Sprite 贴图;GraphicsLib 将它与场景光照组合,得到最终受光颜色。将结果保存为:

graphics/material/ships/GearIn_artizan.png

用 normal 表现表面方向

normal 贴图用 RGB 保存切线空间法线。接近 (128, 128, 255) 的中性蓝表示表面朝向观察者;红色与绿色分量的变化表示表面向左右或上下倾斜,蓝色分量表示朝向观察者的程度。

制作时先从舰船轮廓与装甲高度得到一张连续的高度关系,再转换为切线空间 normal。平坦装甲保持接近中性蓝,舰体边缘、凹槽和隆起逐渐改变方向,透明区继续保持透明。将结果保存为:

graphics/normal/ships/GearIn_artizan.png

normal 的颜色表示方向,不应直接使用原始舰船颜色。过强的高度梯度会让装甲像被切出尖锐沟槽;后面的 magnitude 还能在不重新绘图的情况下整体调整起伏强度。

对齐画布、船体与透明区

将三张图保持为相同像素宽高,舰船中心位于相同像素,朝向一致。导出时保留原画布和透明边缘,原始贴图的中心点与武器槽也使用这套坐标。单独裁掉一张图的透明边缘以后,图片看起来更紧凑,光照却会整体偏到另一处。

可以把三张图放入同一图像文档的三个图层组:原始 Sprite 贴图保持只读,material 与 normal 各自编辑;导出前同时检查画布边界、舰首方向和 alpha。运行后如果亮部整体偏离船体,首先比较三张 PNG 的尺寸和不透明像素包围盒,而不是调整 CSV ID。

编写 texture CSV

创建 data/lights/GearIn_texture_data.csv,写入下面两条纹理映射:

id,type,frame,magnitude,map,path
GearIn_artizan,ship,,,material,graphics/material/ships/GearIn_artizan.png
GearIn_artizan,ship,,1,normal,graphics/normal/ships/GearIn_artizan.png

两行共用 GearIn_artizan 与 ship,因此都进入这艘舰船的纹理登记;map 决定它们分别进入 material 表还是 normal 表。GraphicsLib 用 ID、对象类型和动画帧组成查询键,同一个 ID 可以同时拥有三类 map。

texture CSV 字段速查表

字段当前值读取结果常见错误
idGearIn_artizan对象查询键写成装配 ID 后无法匹配船体
typeship选择舰船纹理表大小写或拼写错误会跳过该行
frame空非动画对象使用第 0 帧舰船填写正数会被丢弃并记录警告
magnitude空/1默认值为 1,normal 行控制起伏强度过大时表面方向显得尖锐
mapmaterial/normal选择三类纹理表之一未使用规定小写值时无法登记
pathgraphics/...指向实际 PNG路径存在拼写差异时加载失败

id 对应对象本身,而不是 CSV 行的任意名称。对于舰船,使用 hull ID;对于武器,使用 weapon ID;对于导弹,使用其 missile hull 或 projectile 关系所使用的 ID。path 从 MOD 根目录开始书写,并保留实际文件名大小写。

在应用加载时登记 texture CSV

[C18-S5] 的应用入口已经初始化 GraphicsLib,并在能力可用时登记 light CSV。纹理映射使用同一个能力分支,在现有入口中加入 TextureData.readTextureDataCSV(...):

@Override
public void onApplicationLoad() {
    ShaderLib.init();

    if (ShaderLib.areShadersAllowed() && ShaderLib.areBuffersAllowed()) {
        LightData.readLightDataCSV("data/lights/GearIn_light_data.csv");
        TextureData.readTextureDataCSV("data/lights/GearIn_texture_data.csv");
    }
}

TextureData.readTextureDataCSV(...) 读取全部数据行,把合法的 ID、对象类型、动画帧和 map 组合加入 GraphicsLib 的纹理注册表。能力判断失败时,这份 MOD 纹理表不会在本次应用运行中登记;能力恢复后需要重新启动游戏,让应用加载入口重新执行。

选择覆盖策略

默认入口允许后读取的数据替换同一查询键下的旧登记:

TextureData.readTextureDataCSV(
        "data/lights/GearIn_texture_data.csv");

只想补充缺失映射时,使用不覆盖入口:

TextureData.readTextureDataCSVNoOverwrite(
        "data/lights/GearIn_texture_data.csv");

重复关系由 ID、对象类型、动画帧和 map 共同确定。覆盖入口让后读取行成为查询结果;不覆盖入口保留已经存在的条目,并跳过对应的重复映射。

选择对象类型与动画帧

type 的值决定 GraphicsLib 把纹理放入哪个对象注册表。CSV 只接受下面 15 个小写值:

对象类型速查表

分组type 值对应对象
舰船ship舰船与战机船体
炮塔主体turret、turretbarrel、turretunder炮塔、炮管与底图
炮塔盖板turretcoversmall、turretcovermedium、turretcoverlarge三种尺寸的炮塔槽盖板
硬点主体hardpoint、hardpointbarrel、hardpointunder硬点、炮管与底图
硬点盖板hardpointcoversmall、hardpointcovermedium、hardpointcoverlarge三种尺寸的硬点槽盖板
导弹missile使用舰船式 Sprite 贴图的导弹
小行星asteroid战斗中的小行星

只有 turret 与 hardpoint 会读取正数 frame。这两类对象可以按动画帧登记不同贴图;其他类型即使填写正数,加载器也会记录不兼容警告并把该帧值丢弃。舰船固定使用第 0 帧,因此示例保持空单元格。

map 则只接受 material、normal 与 surface。surface 行使用相同的 ID、type、frame 和 path 关系,例如 GearIn_artizan,ship,,,surface,graphics/surface/ships/GearIn_artizan.png;本节不把这行加入最终数据。

查询显式纹理条目

TextureData.readTextureDataCSV(...) 完成登记后,可以按登记时使用的四部分键查询 material:

TextureEntry material = TextureData.getTextureData(
        "GearIn_artizan",
        TextureData.TextureDataType.MATERIAL_MAP,
        TextureData.ObjectType.SHIP,
        0);

第一个参数是 hull ID,第二个参数选择 material 表,第三个参数对应 CSV 的 ship。舰船忽略帧参数,这里统一传 0;turret 与 hardpoint 才按具体帧号匹配。ID、map 或对象类型不对应,或者该类贴图的加载开关关闭时,查询返回 null。

普通查询会在需要时加载纹理,但不会返回标记为 autoGen 的 normal。显式登记以及不带该标记的已建立映射,都能按相应键取得。

normal 使用同样的对象键,只替换 map 枚举:

TextureEntry normal = TextureData.getTextureData(
        "GearIn_artizan",
        TextureData.TextureDataType.NORMAL_MAP,
        TextureData.ObjectType.SHIP,
        0);

TextureEntry 将路径、强度、加载状态和 Sprite 贴图放在同一个对象中。查询成功后,spriteName 是 CSV 路径,magnitude 是解析后的数值,sprite 是当前可用的 SpriteAPI;路径不可加载时,普通查询最终返回 null。

TextureEntry 状态速查表

下面的字段描述同一条登记从路径到显存的状态:

字段含义直接观察
sprite已载入的 SpriteAPI可交给渲染流程使用
spriteName原始或缓存纹理路径核对实际资源来源
magnitudeCSV 解析出的强度normal 示例为 1
autoGen是否属于自动生成 normal显式 normal 为 false
validToLoad条目是否允许按路径加载纹理允许加载但尚未驻留时仍可为 true
loaded纹理当前是否已经载入动态加载前后会变化
alwaysPreload对象是否要求常驻预载来自 graphicslib_preload 标签
vramSize估算显存占用单位为字节

loaded 与 validToLoad 描述两个不同阶段:前者表示纹理当前驻留,后者表示它可以在需要时载入。使用 sprite 之前应以查询结果为准;文件路径错误时,条目无法提供可用 Sprite 贴图。

使用自动生成作为替代路径

显式 normal 行提供稳定且由美术人员控制的表面方向。需要兼容尚未制作 normal 的舰船时,把实际舰船对象交给带自动生成能力的查询:

TextureEntry normal = TextureData.getTextureDataWithAutoGen(
        "GearIn_artizan",
        TextureData.TextureDataType.NORMAL_MAP,
        TextureData.ObjectType.SHIP,
        0,
        ship,
        false);

ship 让 GraphicsLib 能从 ShipAPI.getHullSpec().getSpriteName() 找到原始 Sprite 贴图。最后的 false 表示返回前要取得可用的 sprite;设置为 true 时,方法可以返回尚未载入、sprite == null 的条目,因此通常不适合直接使用纹理的代码。

如果相同对象键已经有显式 normal,查询直接返回显式条目。只有 normal 缺失、ship 有效且 autoGenNormals 已启用时,GraphicsLib 才会尝试生成;autoGen 字段能够区分最终来源。

自动生成结果保存在 Starsector/mods/GraphicsLib/cache。游戏版本、已启用 MOD 的 ID 与版本列表共同决定缓存是否继续有效,发生变化后再生成。

修改 Sprite 贴图不会自动改变缓存依据

只修改 PNG 内容、保持游戏与 MOD 版本信息不变时,现有自动法线缓存仍可能继续使用。测试工匠新贴图时,关闭游戏后移除 Starsector/mods/GraphicsLib/cache/GearIn_artizan___SHIP_normal.png,再启动并触发生成,比较新结果。

控制自动生成范围

需要主动建立某个 Sprite 贴图的 material、normal 与 surface 映射时,可以把对象键和原始 Sprite 贴图路径交给 mapSpriteToMNSWithAutoGen(...):

TextureData.mapSpriteToMNSWithAutoGen(
        "GearIn_artizan",
        "graphics/ships/GearIn_artizan.png",
        TextureData.ObjectType.SHIP,
        0,
        true,
        false);

前四个参数确定映射键,第五个参数允许生成缺失的 normal;最后一个参数为 true 时,生成结果不带自动生成标记,普通兼容路径保持为 false。自动查询识别 graphicslib_no_autogen 以限制生成,graphicslib_autogen_override 则影响结果标记;已有显式 normal 继续优先使用。

编者更愿意为需要突出装甲结构的舰船制作显式 normal。 自动生成根据原始 Sprite 贴图的亮度推算高度,再生成表面方向,涂装和原图阴影也会进入这份推算。它能提供通用受光效果,具体凹槽和装甲隆起则由自己的高度关系控制。

autoGenNormalMap(...) 直接从一张 Sprite 贴图生成 normal,并返回生成后的 SpriteAPI:

SpriteAPI generated = TextureData.autoGenNormalMap(
        "graphics/ships/GearIn_artizan.png",
        "GearIn_artizan",
        TextureData.ObjectType.SHIP,
        0);

这个入口适合已经掌握对象键和缓存规则的专用工具。常规战斗代码使用 getTextureDataWithAutoGen(...) 即可;全局扫描入口 autoGenMissingNormalMaps() 由 GraphicsLib 的初始化流程负责。

理解缓存、按需加载与预载

GraphicsLib 默认按当前战斗需要加载舰船、武器和导弹纹理,并卸载已经不再需要的条目。遗漏的登记会在首次查询时按需加载,因此 validToLoad == true 与 loaded == false 可以同时出现;完成加载后,loaded 和 sprite 才反映当前可用状态。

设置 preloadAllMaps = true 会在预载阶段加载全部 material、normal 与 surface 贴图。它能减少首次使用时的加载停顿,也会提前占用全部贴图的显存。对象标签 graphicslib_preload 只让对应对象的贴图常驻预载,适合少量关键舰船或武器。

需要在战斗脚本中等待预载完成时,读取战斗引擎的 custom data:

if (engine.getCustomData().containsKey(ShaderHook.TEXTURE_PRELOAD_KEY)) {
    TextureEntry normal = TextureData.getTextureDataWithAutoGen(
            "GearIn_artizan",
            TextureData.TextureDataType.NORMAL_MAP,
            TextureData.ObjectType.SHIP,
            0,
            ship,
            false);
}

ShaderHook.TEXTURE_PRELOAD_KEY 与 TextureData.ALWAYS_PRELOAD_TAG 的字符串值都是 graphicslib_preload,前者是战斗状态键,后者是对象标签。两个值存在于不同容器,读取时要分别使用 engine.getCustomData() 与对象 spec 的标签接口。

常用字段与方法速查表

入口关键参数返回或结果
getTextureData(...)ID、map、对象类型、帧查询显式登记并按需加载,缺失时返回 null
getTextureDataWithAutoGen(...)显式查询参数、实际对象、unloadedOk优先显式条目,必要时生成 normal
mapSpriteToMNSWithAutoGen(...)对象键、Sprite 贴图路径、类型、帧、生成开关、覆盖开关建立三类纹理映射并处理缺失 normal
autoGenNormalMap(...)Sprite 贴图路径、对象键、类型、帧返回自动生成的 normal Sprite 贴图
autoGenMissingNormalMaps()无由 GraphicsLib 初始化流程扫描缺失 normal
TextureEntry.spriteName—显式路径或缓存路径
TextureEntry.magnitude—normal 起伏强度,默认 1
TextureEntry.loaded—当前是否已经载入
TextureEntry.vramSize—估算显存占用,单位为字节

完整最小例

应用加载入口同时保留 [C18-S5] 的 light 登记,并加入本节的 texture 登记:

@Override
public void onApplicationLoad() {
    ShaderLib.init();

    if (ShaderLib.areShadersAllowed() && ShaderLib.areBuffersAllowed()) {
        LightData.readLightDataCSV("data/lights/GearIn_light_data.csv");
        TextureData.readTextureDataCSV("data/lights/GearIn_texture_data.csv");
    }
}

最终目录保留原始 Sprite 贴图,并为 GraphicsLib 增加两张坐标完全一致的贴图:

graphics/ships/GearIn_artizan.png
graphics/material/ships/GearIn_artizan.png
graphics/normal/ships/GearIn_artizan.png
data/lights/GearIn_texture_data.csv

GearIn_texture_data.csv 使用以下完整内容:

id,type,frame,magnitude,map,path
GearIn_artizan,ship,,,material,graphics/material/ships/GearIn_artizan.png
GearIn_artizan,ship,,1,normal,graphics/normal/ships/GearIn_artizan.png

验证方案

前置数据:[C18-S5] 的入口已经初始化 GraphicsLib,三张 GearIn_artizan PNG 已按正文目录准备,[C18-S6] 的动态光源能够在战斗中照射测试舰船。

  1. 用相同画布导出 material 与 normal PNG,核对三张图片的像素尺寸、舰船中心、不透明像素包围盒和舰首方向。
  2. 启动游戏,确认 onApplicationLoad() 读取 GearIn_texture_data.csv,日志中没有路径、type、map 或 frame 警告。
  3. 用同一查询键分别测试覆盖与不覆盖入口,确认最终 TextureEntry 来自预期数据行。
  4. 查询 GearIn_artizan 的 material 与 normal,核对 spriteName、magnitude、autoGen、validToLoad 和 loaded。
  5. 使用 [C18-S6] 的动态光源照射工匠级,转动舰船并观察 material 颜色、normal 明暗方向与船体同步旋转。
  6. 临时移除 normal 数据行并启用 autoGenNormals,确认查询返回 autoGen == true,同时在 Starsector/mods/GraphicsLib/cache 产生缓存。
  7. 分别给测试船体加入 graphicslib_no_autogen、graphicslib_autogen_override 与 graphicslib_preload,核对生成来源和预载状态。
  8. 分别启用和关闭 preloadAllMaps,比较加载日志、第一次进入战斗的停顿和全部 TextureEntry.vramSize 之和。
  9. 依次制造错误 ID、错误 type、错误 map、缺失路径、错位画布和错误 frame,核对下面列出的症状与修正结果。

预期结果:

  • texture CSV 在应用加载阶段进入注册表,覆盖策略与同一查询键的预期一致;
  • 两条显式登记都以 GearIn_artizan、SHIP 和第 0 帧命中,normal 的 magnitude 为 1;
  • 动态光下的颜色与表面方向贴合原始舰船轮廓,透明区没有额外受光像素;
  • 移除显式 normal 后,自动生成结果来自缓存路径并标记 autoGen;
  • 动态加载只让当前战斗需要的条目驻留,全量预载则提前增加相应显存占用;
  • 三个标签分别改变自动生成许可、生成结果选择与常驻预载范围。

故障分析

  • 查询结果为 null:ID、对象类型、map、适用的动画帧、加载开关或资源路径没有对应到可用条目。

    • 解决方案:核对登记与加载开关;turret 和 hardpoint 另核对帧号,并确认 PNG 能够加载。
  • 贴图整体偏离舰船:material 或 normal 的画布、中心、透明边界或朝向与原始 Sprite 贴图不同。

    • 解决方案:在同一画布中重新对齐三张图后导出。
  • 表面凹凸方向相反或过于尖锐:normal 通道方向错误,或 magnitude 过大。

    • 解决方案:修正法线通道,并从 magnitude = 1 开始校准。
  • 缺失 normal 后没有自动生成:全局开关、对象标签、实际对象参数或原始 Sprite 贴图路径阻止了生成。

    • 解决方案:确认 autoGenNormals 已启用、对象未带禁止标签,并把实际 ShipAPI 传入查询。
  • 第一次进入战斗出现明显停顿:大量纹理在首次使用时同时按需载入。

    • 解决方案:只给关键对象添加 graphicslib_preload,再以显存统计决定是否启用 preloadAllMaps。

总结

工匠级通过船体 ID 与 SHIP 类型取得两种 map:画布对齐决定采样位置,material 和 normal 分别提供颜色与表面方向。查询再按加载状态取得资源;自动生成、显式制作和预载范围,则分别依据表面结构的控制需要与显存占用选择。

建议参考项

  • org.dark.shaders.util.TextureData:CSV 登记、纹理查询、自动生成与加载策略;
  • org.dark.shaders.util.TextureEntry:纹理路径、强度、来源和驻留状态;
  • org.dark.shaders.util.ShaderHook:战斗纹理预载完成状态;
  • Starsector/mods/GraphicsLib/data/lights/core_texture_data.csv:对象类型与字段格式;
  • Starsector/mods/GraphicsLib/GRAPHICS_OPTIONS.ini:自动生成和预载配置。
在 GitHub 上编辑此页
上次更新: 2026/10/14 12:25
贡献者: 1847905557
上一页
创建 GraphicsLib 动态光源
下一页
配置 MagicLib 自动尾迹