Skip to content

SCAPI24/su-api-example-mod-set

Repository files navigation

SuAPI Example Mod Set

Survivalcraft 2 SuAPI Mod 示例集合,演示 SuAPI 接口的各种用法。

项目特性

  • net8.0 — 所有 Mod 基于 .NET 8.0,SDK 样式 csproj
  • SuAPI 接口 — 通过 IModEventBus / IModInjector / IModParentField / IModParentMethod / IModResource 调整游戏行为,不修改原始代码
  • IsMergeLib — 支持 IsMergeLib=true(DLL 放 Lib/,双端共用)或 false(按平台放 Lib/X64 + Lib/Arm64
  • Python zipfile 打包 — .scmod 必须用 Python zipfile 打包,确保正斜杠路径

使用方法

编译 Mod

从项目根目录运行(global.json 锁定 SDK 8.0.402):

# Windows
dotnet build Mod/<ModName>/<ModName>.csproj -c Debug --framework net8.0

# Android(需要 net8.0-android 工作负载)
dotnet build Mod/<ModName>/<ModName>.csproj -c Debug --framework net8.0-android

IsMergeLib=true 的 Mod 只需编译 Windows 版(单 TFM net8.0),DLL 双端共用。

打包 .scmod

import zipfile, os

MOD_NAME = "YourMod"
MOD_DIR = r"D:\...\Mod\YourMod"
MODS_DIR = r"D:\...\publish\win-x64\Mods"

modinfo = os.path.join(MOD_DIR, "ModInfo.xml")
win_dll = os.path.join(MOD_DIR, "bin", "Debug", "net8.0", "Obfuscar", f"{MOD_NAME}.dll")

with zipfile.ZipFile(os.path.join(MODS_DIR, f"[SuAPI]你的Mod名.scmod"), 'w', zipfile.ZIP_DEFLATED) as zf:
    zf.write(modinfo, "ModInfo.xml")
    zf.write(win_dll, f"Lib/{MOD_NAME}.dll")          # IsMergeLib=true
    # zf.write(win_dll, f"Lib/X64/{MOD_NAME}.dll")     # IsMergeLib=false
    # zf.write(android_dll, f"Lib/Arm64/{MOD_NAME}.dll") # IsMergeLib=false

部署

将 .scmod 放入游戏 Mods/ 目录即可加载。

ModInfo.xml 格式

<?xml version="1.0" encoding="UTF-8"?>
<Mod>
    <ModInfo>
        <Identifier>YourMod</Identifier>
        <LocalizedName>
            <Text lang="en_US">Your Mod</Text>
            <Text lang="zh_CN">你的Mod</Text>
        </LocalizedName>
        <ModVersion>
            <Version>1.0.0</Version>
            <APIVersion>2.1.0</APIVersion>
        </ModVersion>
        <Asset>
            <ContentRoot>Content</ContentRoot>
        </Asset>
        <IsMergeLib>true</IsMergeLib>
    </ModInfo>
    <Dependencies>
        <!-- <Dependency><ModInfo><Identifier>Comms</Identifier></ModInfo></Dependency> -->
    </Dependencies>
</Mod>

已收录 Mod

SurvivalcraftMiniMap

MiniMap 截图

小地图 Mod,通过 ComponentTemplate 向 Player 挂载地图组件,实时显示玩家位置和周围地形。

WatchMod

WatchMod 截图

手表 Mod,ComponentTemplate+IUpdateable 独立组件模式,handcrafting slot 2 放置 RealTimeClockBlock 时显示游戏时间。不替换 SubsystemGameWidgets,与其他 UI Mod 兼容。

ConsoleMod

ConsoleMod 截图

游戏内控制台,按 · 打开,支持 move +x300 等指令。Windows 端用 KeyboardInput 内联输入,Android 端用 Keyboard.ShowKeyboard() 对话框输入。

StringInterceptor

StringInterceptor 截图

字符串翻译 Mod,Widget 树文本拦截 + IStringProcessor 翻译接口,将游戏界面翻译为中文。演示 LoadingManager.QueueItemReplaceItem 用法。

RainWithoutDawn

RainWithoutDawn 截图

Subsystem 替换天气系统,移除下雨逻辑。简洁的 Subsystem 替换范例。

MemoryBankDrawMod

MemoryBankDrawMod 截图

Memory Bank 绘图编辑器,替换 SubsystemMemoryBankBlockBehavior,增加 16×16 像素 Draw 模式,16 色画笔和拖拽填充。IsMergeLib=true,单 DLL 双端运行。

ScMultiplayer

多人联机 Mod,基于 Comms 通信库。演示复杂 Mod:Dependencies 声明、LoadingManager.ReplaceItem、条件编译。

其他 Mod

Mod 类型 说明
TemperatureImmunity Component 替换 替换体温组件,保持恒温
Comms 联机通信库 SuAPI 联机 Mod 通信基础库,ScMultiplayer 依赖

资源加载

Mod 有两种资源加载方式,可按需混用:

1. scmod Content/ 目录 → ContentCache

将资源文件放入 scmod 的 Content/ 目录,ModLoader 启动时自动提取并缓存到 ContentCache

Key 规则Content/{relativePath}.{ext}ContentCache.Get<T>("Mod/{relativePath}")(去掉 Content/ 前缀和扩展名)

Content/SuConsoleButton.png  → ContentCache.Get<Texture2D>("Mod/SuConsoleButton")
Content/Fonts/chinese12.png  → ContentCache.Get<Texture2D>("Mod/Fonts/chinese12")
Content/zh_CN.xml            → ContentCache.Get<XElement>("Mod/zh_CN")

代码

using Engine.Content;
var tex = ContentCache.Get<Texture2D>("Mod/SuConsoleButton");

打包

zf.write("Content/SuConsoleButton.png", "Content/SuConsoleButton.png")

适用:纹理、字体、翻译 XML、模型等需要运行时替换的资源。优点是无需重新编译 DLL 即可替换资源。

2. DLL 嵌入资源 → GetManifestResourceStream

将资源编译进 DLL 作为嵌入资源,运行时通过 Assembly.GetManifestResourceStream 读取。

Key 规则:csproj 中 <EmbeddedResource Include="Content\YourFile.png" /> → 资源名 {Namespace}.{Content.YourFile.png}

csproj

<ItemGroup>
  <EmbeddedResource Include="Content\YourButton_Pressed.png" />
</ItemGroup>

代码

using System.Reflection;
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleMod.Content.YourButton_Pressed.png");
var tex = Texture2D.Load(stream);
stream.Dispose();

适用:不希望用户替换的资源(如按下状态纹理)、小体积资源。优点是资源与 DLL 一体,不会丢失。

混用示例(ConsoleMod)

普通按钮纹理放 Content/(可替换),按下纹理嵌入 DLL(不可替换):

<!-- ConsoleMod.csproj -->
<ItemGroup>
  <EmbeddedResource Include="Content\SuConsoleButton_Pressed.png" />
</ItemGroup>
// 普通纹理:从 ContentCache 加载(scmod Content/ 目录)
m_buttonNormalTex = ContentCache.Get<Texture2D>("Mod/SuConsoleButton");
// 按下纹理:从 DLL 嵌入资源加载
m_buttonPressedTex = LoadEmbeddedTexture("ConsoleMod.Content.SuConsoleButton_Pressed.png");

运行时铁律

  1. ModLoader 依赖加载 — .scmod 内 DLL 不会自动全部加载,只有 Identifier 同名的和 <Dependencies> 声明的才会被加载
  2. ReplaceItem name 匹配LoadingManager.ReplaceItem(name, action) 的 name 是 QueueItem 注册名("Initialize PlayScreen"),不是 Screen 名
  3. EventBus 静默吞异常 — 回调异常只写 Console.WriteLine,不记入 Game.log
  4. Release Android AOT/Linker 裁剪 — 主程序未使用的方法会被 linker 移除,Mod 使用→MissingMethodException。避免 Linq/委托排序/params 构造函数
  5. SC 坐标系 Y 向上 — 定位参数不能耦合大小参数,必须拆分为 visualRadiusPx + marginX/Y
  6. 禁止提交诊断 Log — 临时调试日志验证后必须移除
  7. Storage.ProcessPath — 只识别 app:data: 协议,绝对路径抛异常
  8. .scmod ZIP 正斜杠 — 必须用 Python zipfile 打包,Compress-Archive 反斜杠路径→ModLoader 匹配失败
  9. ModInfo.xml 根目录 — 打包时 ModInfo.xml 必须在 ZIP 根目录
  10. PowerShell [] 通配符 — 操作含 [SuAPI] 路径时必须用 -LiteralPath

相关仓库

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Packages

 
 
 

Contributors

Languages