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 打包,确保正斜杠路径
从项目根目录运行(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-androidIsMergeLib=true 的 Mod 只需编译 Windows 版(单 TFM net8.0),DLL 双端共用。
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/ 目录即可加载。
<?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,通过 ComponentTemplate 向 Player 挂载地图组件,实时显示玩家位置和周围地形。
手表 Mod,ComponentTemplate+IUpdateable 独立组件模式,handcrafting slot 2 放置 RealTimeClockBlock 时显示游戏时间。不替换 SubsystemGameWidgets,与其他 UI Mod 兼容。
游戏内控制台,按 · 打开,支持 move +x300 等指令。Windows 端用 KeyboardInput 内联输入,Android 端用 Keyboard.ShowKeyboard() 对话框输入。
字符串翻译 Mod,Widget 树文本拦截 + IStringProcessor 翻译接口,将游戏界面翻译为中文。演示 LoadingManager.QueueItem 和 ReplaceItem 用法。
Subsystem 替换天气系统,移除下雨逻辑。简洁的 Subsystem 替换范例。
Memory Bank 绘图编辑器,替换 SubsystemMemoryBankBlockBehavior,增加 16×16 像素 Draw 模式,16 色画笔和拖拽填充。IsMergeLib=true,单 DLL 双端运行。
多人联机 Mod,基于 Comms 通信库。演示复杂 Mod:Dependencies 声明、LoadingManager.ReplaceItem、条件编译。
| Mod | 类型 | 说明 |
|---|---|---|
| TemperatureImmunity | Component 替换 | 替换体温组件,保持恒温 |
| Comms | 联机通信库 | SuAPI 联机 Mod 通信基础库,ScMultiplayer 依赖 |
Mod 有两种资源加载方式,可按需混用:
将资源文件放入 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 即可替换资源。
将资源编译进 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 一体,不会丢失。
普通按钮纹理放 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");- ModLoader 依赖加载 — .scmod 内 DLL 不会自动全部加载,只有 Identifier 同名的和
<Dependencies>声明的才会被加载 - ReplaceItem name 匹配 —
LoadingManager.ReplaceItem(name, action)的 name 是 QueueItem 注册名("Initialize PlayScreen"),不是 Screen 名 - EventBus 静默吞异常 — 回调异常只写 Console.WriteLine,不记入 Game.log
- Release Android AOT/Linker 裁剪 — 主程序未使用的方法会被 linker 移除,Mod 使用→MissingMethodException。避免 Linq/委托排序/params 构造函数
- SC 坐标系 Y 向上 — 定位参数不能耦合大小参数,必须拆分为 visualRadiusPx + marginX/Y
- 禁止提交诊断 Log — 临时调试日志验证后必须移除
- Storage.ProcessPath — 只识别
app:和data:协议,绝对路径抛异常 - .scmod ZIP 正斜杠 — 必须用 Python zipfile 打包,Compress-Archive 反斜杠路径→ModLoader 匹配失败
- ModInfo.xml 根目录 — 打包时 ModInfo.xml 必须在 ZIP 根目录
- PowerShell
[]通配符 — 操作含[SuAPI]路径时必须用-LiteralPath





