Skip to content

自定义托管程序集 ​

当项目需要拆分业务代码,或引入项目自有的第三方托管 DLL 时,可以让这些 DLL 随 GameEntry.dll 一起部署并加载。这个能力只面向项目自己的 C# 程序集;SDK、运行时和依赖库提供的程序集由当前编辑器、SDK 与依赖库版本统一提供,项目代码不要声明同名 DLL。

若引用的是带项目 ID、数据或资源的 SCE 依赖库项目,按依赖库项目指南同时配置 libs.json 和 csproj 编译引用;本地联调再配置 local_libs.json 及所用宿主的库上下文。库由依赖包加载,csproj 引用路径只用于编译。

推荐接入方式 ​

优先把额外程序集作为 src/GameEntry.csproj 的普通 .NET 依赖管理,然后使用编辑器的正常编译、调试和发布流程。常见方式包括:

  • 使用 ProjectReference 拆分项目业务代码。
  • 使用 PackageReference 引入适配当前运行环境的托管包。
  • 使用带明确来源的 Reference 引入项目自有 DLL。

例如把共享业务库放在项目 src/ 旁边:

xml
<ItemGroup>
  <ProjectReference Include="..\MyGame.Shared\MyGame.Shared.csproj" />
</ItemGroup>

如果必须引用已经构建好的托管 DLL,建议把它放到项目明确管理的目录中,并用 HintPath 指向它:

xml
<ItemGroup>
  <Reference Include="MyGame.Plugin">
    <HintPath>..\libs\MyGame.Plugin.dll</HintPath>
  </Reference>
</ItemGroup>

无论使用哪种方式,都需要分别通过客户端和服务端配置构建:

powershell
dotnet build src/GameEntry.csproj -c Server-Debug
dotnet build src/GameEntry.csproj -c Client-Debug

部署位置 ​

编辑器的正常调试和发布流程会负责把项目产物部署到运行时 AppBundle。若需要检查最终位置,规则如下:

运行端项目自有程序集位置
服务端AppBundle/managed/<程序集名>.dll
客户端ui/AppBundle/managed/<程序集名>.dll

这些 DLL 与对应运行端的 GameEntry.dll 同级。只用于某一端的程序集只需要出现在对应端的目录中;双端共用的程序集需要同时能通过 Server-* 和 Client-* 配置构建,并分别出现在两个目录中。

命名边界 ​

GameEntry.dll 始终是项目入口程序集。除 GameEntry.dll 之外,项目自有 DLL 必须使用项目自己的唯一名称,并遵守下面的边界:

  • 不要与 SDK 自带程序集同名。
  • 不要与项目依赖库 ID 同名。
  • 若某个 DLL 名称对应一个项目依赖库 ID,该 DLL 由对应依赖库提供,不由主项目 AppBundle 提供。

推荐使用带项目名前缀的程序集名,例如 MyGame.Shared.dll、MyGame.Combat.dll、MyGame.Plugin.Inventory.dll。不要使用 GameCore.dll、GameUI.dll、System.*.dll,也不要使用已添加到项目依赖列表中的库 ID 作为 DLL 名称。

如果构建产生 .pdb 或 satellite resource assemblies,可以随项目自有 DLL 一起部署,便于调试或本地化资源加载;命名边界仍以实际 DLL 名称为准。

调试不编译时的手动部署 ​

debug_start_no_compile 只会跳过编译并启动调试,不会替你更新 AppBundle 中的 DLL。使用这个调试循环前,先完成对应配置构建,再把当前产物复制到对应端的 managed 目录。

示例:

powershell
$ProjectRoot = "D:\Maps\MyMap"
$ServerOut = Join-Path $ProjectRoot "src\bin\Server-Debug\net9.0"
$ClientOut = Join-Path $ProjectRoot "src\bin\Client-Debug\net9.0"

Copy-Item -LiteralPath (Join-Path $ServerOut "GameEntry.dll") -Destination (Join-Path $ProjectRoot "AppBundle\managed\GameEntry.dll") -Force
Copy-Item -LiteralPath (Join-Path $ClientOut "GameEntry.dll") -Destination (Join-Path $ProjectRoot "ui\AppBundle\managed\GameEntry.dll") -Force

Copy-Item -LiteralPath (Join-Path $ServerOut "MyGame.Shared.dll") -Destination (Join-Path $ProjectRoot "AppBundle\managed\MyGame.Shared.dll") -Force
Copy-Item -LiteralPath (Join-Path $ClientOut "MyGame.Shared.dll") -Destination (Join-Path $ProjectRoot "ui\AppBundle\managed\MyGame.Shared.dll") -Force

如果某个程序集只在客户端或只在服务端使用,只复制对应配置的输出即可。手动复制时只复制项目自己的输出程序集;SDK 与依赖库内容应由编辑器、SDK 和依赖库版本管理。

常见排查 ​

  • FileNotFoundException:确认目标 DLL 已经出现在当前运行端的 managed 目录,且不是只复制到了另一端。
  • TypeLoadException 或 MissingMethodException:确认客户端和服务端配置都已重新构建,旧 DLL 没有残留在 AppBundle 中。
  • 自定义 DLL 已放到 managed 目录但没有生效:先确认 DLL 文件名没有与 SDK 自带程序集或项目依赖库 ID 重名。重名时运行时会按 SDK 或依赖库的来源加载,不会把主项目 AppBundle 中的同名 DLL 当作项目自有 DLL 使用。
  • 正常编译能跑,debug_start_no_compile 跑旧逻辑:确认已把最新 GameEntry.dll 和项目自有 DLL 复制到 managed 目录。
  • 新增 DLL 后发布包缺失:先使用编辑器正常调试/发布流程验证;需要手动路径时,检查程序集名称是否与 SDK 自带程序集或依赖库 ID 冲突。

相关调试流程见 星火 2.0 发布、调试与 AI 辅助开发流程 和 纯客户端调试。AI 通过 MCP 启动不编译调试时,还应参考 SCE DebugTools MCP Skill。