主题
依赖库项目:引用、本地联调与运行时加载
地图项目引用带 C# 代码的依赖库时,需要同时配置项目根目录的 libs.json 和 src/GameEntry.csproj 中的编译引用。本地联调还需要让编辑器找到库项目目录。三者各有职责,不会相互替代。
配置分别负责什么
| 配置 | 用途 | 不会自动完成的事 |
|---|---|---|
地图根目录 libs.json | 声明库 ID 和库的逻辑路径,供依赖解析、数据与资源加载、运行时包查找使用 | 不会为 C# 编译器添加工程或 DLL 引用 |
地图 src/GameEntry.csproj 中的 ProjectReference 或 Reference | 为编译器提供库类型、方法和程序集身份 | 不会替代 libs.json,也不会发布依赖库包 |
地图根目录 local_libs.json | 本机开发时,将已声明的库 ID 映射到本地库项目根目录 | 不会声明新依赖,也不会修改 csproj |
Headless 启动参数 --lib <ID=路径> | 显式配置无头数据、触发器宿主的库解析上下文 | 不会修改上述文件,也不会添加编译引用 |
文件名是 local_libs.json,带复数 s。只使用已安装、已发布的库时,不必为它添加本地覆盖。纯数据或资源库可以没有 C# 工程;只有需要编译引用其代码时,才需要相应的 C# 引用。
一份本地联调配置
假设地图在 D:/Games/MyMap,库项目在 D:/Libraries/CombatLibrary,库的 project/map_settings.json 中 ProjectName 为 l_combat、IsLib 为 true。库目录名、显示名和项目 ID 可以不同;下面所有 ID 都使用 l_combat。
1. 声明依赖
在地图根目录的 libs.json 中追加库,并保留项目已有依赖。例如:
json
{
"gamesystemui": "GameSystemUI",
"l_combat": "CombatLibrary"
}左侧是库项目 ID,右侧是库的逻辑相对路径,不是版本号或本机 csproj 路径。沿用编辑器为库生成的路径;本机绝对路径放在本地覆盖中。库自身也可通过自己的 libs.json 声明依赖,形成递归依赖关系。
2. 添加编译引用
如果直接开发库源码,在地图 src/GameEntry.csproj 中添加:
xml
<ItemGroup>
<ProjectReference Include="D:/Libraries/CombatLibrary/src/l_combat.csproj" />
</ItemGroup>库项目可以放在编译机可访问的任意位置,无需复制进地图目录。Include 可以使用绝对路径,也可以使用相对当前 csproj 的路径;团队协作时可通过共享目录约定或 MSBuild 属性提供路径。双方应使用兼容的 SDK、目标框架和 Server-* / Client-* 配置。直接构建 csproj 时,被引用工程会按对应配置参与构建;通过解决方案构建时还要检查解决方案的配置映射。
若使用已经构建好的库 DLL,则使用 Reference + HintPath,按运行端选择产物。以下路径仅为示例:
xml
<ItemGroup Condition="'$(Configuration)' == 'Server-Debug' Or '$(Configuration)' == 'Server-Release'">
<Reference Include="l_combat">
<HintPath>D:/Libraries/CombatLibrary/AppBundle/managed/l_combat.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Client-Debug' Or '$(Configuration)' == 'Client-Release' Or '$(Configuration)' == 'Client-Resource'">
<Reference Include="l_combat">
<HintPath>D:/Libraries/CombatLibrary/ui/AppBundle/managed/l_combat.dll</HintPath>
</Reference>
</ItemGroup>同一个库选择适合自己的引用方式,避免同时引用它的工程与旧 DLL。HintPath 方式要求先生成对应端的新产物;只使用某一端代码时,将引用和调用限制在对应端。
3. 指定本地库来源
在地图根目录添加 local_libs.json:
json
{
"l_combat": "D:/Libraries/CombatLibrary"
}这里指向包含 project/、libs.json、res/ 等内容的库项目根目录,不是 src/ 或 DLL 文件。GUI 依赖管理中的本地库选择也使用该文件。库 ID 仍需存在于 libs.json 的依赖链中;仅写本地覆盖不会让库成为依赖。
本地路径属于开发机配置,不应成为其他作者或正式玩家运行项目的前提。不要把个人绝对路径当成可共享的发布依赖。
4. Headless 的库解析
Headless 的托管数据、触发器加载当前不自动读取 local_libs.json,本地联调应额外传入 --lib。沿用上例的逻辑路径 CombatLibrary,可在原启动命令上追加:
text
--lib l_combat=D:/Libraries/CombatLibrary当前解析器会尝试在覆盖路径下拼接 libs.json 的相对路径;覆盖目录末段与该相对路径末段相同时,也支持直接传库根目录。因此上例可直接使用 CombatLibrary 根目录,也可传其父目录 D:/Libraries。目录名不同或存在多层逻辑路径时,应按该规则提供可解析的目录布局,并检查宿主实际加载的库路径。参数可重复提供不同库的覆盖。
--lib 配置的是托管宿主上下文,不能代替本地调试客户端使用的 local_libs.json。同一次开发应让 csproj 引用、GUI/客户端本地覆盖与 Headless 上下文指向同一份库,重新打开或加载项目后确认依赖诊断已消除。宿主选择与完整启动方式见无头编辑器指南。
运行时怎样找到 DLL
ProjectReference.Include 和 Reference.HintPath 是编译路径。实际游戏运行时不会按这些 csproj 路径打开开发机上的工程或 DLL。
运行时根据请求的程序集名,在依赖映射中查找同名库 ID,再从该库包的 AppBundle/managed/<程序集名>.dll 加载。客户端对应库项目的 ui/AppBundle/managed/ 内容,服务端对应 AppBundle/managed/ 内容;本地调试可通过本地库覆盖解析库内容,正式运行使用已分发的依赖包。
因此,带代码的依赖库必须满足:库项目 ID、AssemblyName 和输出 DLL 基名大小写不敏感地一致。例如 ID 为 l_combat 的库提供 l_combat.dll;已有 gamesparkcore / GameSparkCore.dll 也符合规则。GUI 和 Headless 新建库会将主 csproj、程序集及输出文件名与项目 ID 对齐;普通地图入口继续是 GameEntry.dll。csproj 文件名自身不是运行时的查找键,已有工程应检查最终程序集身份和产物,而非只重命名文件。
编译器可能将引用 DLL 复制进地图构建输出,但这不替代依赖库的包内容。不要通过在地图的 managed 中放一个同名 DLL 来覆盖已声明的库;项目自有辅助 DLL 的部署方式见自定义托管程序集。
构建、验证与发布
- 保存并生成库的数据、触发器代码,构建库的客户端和服务端产物,按需要统计资源、生成动画与碰撞。
ProjectReference的编译不等于完成库的全部资源准备和发布。 - 保存并构建引用地图的
Server-Debug与Client-Debug;涉及资源统计时也检查Client-Resource引用。确认地图编译所用的库接口与运行时解析的库版本一致。 - 在引用地图中调试库逻辑和数据。用户已打开目标地图的 GUI 时优先复用;需要无头工作流时配置对应库上下文。
- 正式发布前,先通过 GUI 的依赖库上传/预制功能发布流程完成库内容、元数据与审核,再确认引用地图在目标环境能取得相应依赖。Headless 的游戏发布工具不能替代库的商店发布流程。
- 在不依赖个人本地覆盖的环境中核对库包版本、双端 DLL 和资源,再发布引用地图。新增依赖、调整公开接口或修改资源后,都需重新验证。
常见问题
| 现象 | 优先检查 |
|---|---|
| 数据编辑器能看到库,但 C# 找不到命名空间或类型 | csproj 是否添加了正确工程/DLL 的编译引用,配置与 SDK 是否匹配 |
| 编译成功,运行时报缺程序集或仍执行旧库逻辑 | libs.json、库 ID 与程序集身份、实际加载的本地/发布包来源、双端产物是否更新 |
| 本地库代码已改,数据或资源仍来自旧包 | local_libs.json 是否映射正确项目根目录;Headless 是否配置了对应 --lib 并重新加载 |
| 只有服务端或客户端失败 | 是否误引用另一端 DLL;相应 Server-* / Client-* 构建与库包是否齐全 |
| 自己机器正常,换机器或正式运行失败 | 是否只配置了本机编译路径或本地覆盖,缺少可分发的依赖声明、库包或匹配版本 |