开发者¶
本页介绍如何从源码构建 PracLab 的两层组件,以及项目结构说明。部署产物请参考安装部署。
1. 编译依赖¶
1.1 L1(C# 插件)¶
| 依赖 | 版本 | 说明 |
|---|---|---|
| .NET SDK | 10.0+ | 编译 L1 |
| CounterStrikeSharp.API | 1.0.371+ | NuGet 自动还原 |
1.2 L2(C++ Metamod 插件)¶
| 依赖 | 版本 | 说明 |
|---|---|---|
| Visual Studio 2022+ | MSVC 14.51+ | Windows 编译 |
| CMake | 3.20+ | 构建系统 |
| Ninja | 任意 | CMake 生成器 |
| HL2SDK CS2 | 与服务器匹配 | 环境变量 HL2SDKCS2 |
| Metamod:Source 源码 | 与服务器匹配 | 环境变量 MMSOURCE_DEV |
| protoc | 3.21.x | 环境变量 PROTOC |
| funchook | v1.1.3 | CMake FetchContent 自动拉取(或本地源码) |
| nlohmann/json | v3.11.3 | CMake FetchContent 自动拉取(或本地源码) |
2. 构建 L1(PracLab C# 插件)¶
# 在仓库根目录执行
dotnet build PracLab.csproj -c Release
产物路径:
bin/Release/net10.0/
├── PracLab.dll # 主程序集
└── lang/
├── zh-CN.json # 中文本地化(构建时自动复制)
└── en.json # 英文本地化
3. 构建 L2(PracLabReplayEngine C++ 插件)¶
3.1 准备 SDK¶
将 HL2SDK CS2、Metamod 源码、protoc 解压到 d:\PracLab\deps\:
deps/
├── hl2sdk-cs2/
├── metamod-source/
├── protoc-3.21.8/
│ └── bin/protoc.exe
├── funchook/ # funchook 源码(可选,否则 CMake 在线拉取)
└── nlohmann_json/ # nlohmann/json 源码(可选,否则 CMake 在线拉取)
3.2 配置 CMake¶
cd d:\PracLab\replay-engine
.\configure.ps1
configure.ps1 会自动设置 MSVC 环境变量、清理旧缓存并用 Ninja 生成 Release 构建目录。脚本内硬编码了 MSVC 与 Windows SDK 路径,环境不同请按实际情况修改。
3.3 编译¶
.\build.ps1
成功时输出:
=== SUCCESS ===
DLL: d:\PracLab\replay-engine\out\build\x64-Release\package\addons\PracLabReplayEngine\bin\win64\PracLabReplayEngine.dll
Size: XXX.XX KB
3.4 关键构建约束¶
以下源于引擎行为与项目规范:
- protoc 版本:为 3.21.x,CMakeLists.txt 会校验。
- 静态运行时:Windows 使用
/MT(静态链接 CRT),保证插件可独立部署。 - protoc 生成代码:
.pb.h中类的final关键字会被自动移除,以允许PlayerCommand继承CSGOUserCmdPB。 - gamedata.json:包含引擎函数签名,CS2 更新后可能需要重新扫描签名。详见
replay-engine/configs/addons/PracLabReplayEngine/gamedata.json。
4. 项目结构¶
PracLab/
├── PracLab.cs # 插件主类(路由表/门控/配置加载/共享数据)
├── PracLab.csproj # .NET 10 项目文件
├── Commands/ # 各功能 partial 类
│ ├── BotCommands.cs # .bot / .crouchbot / .kick / .kickall
│ ├── BotCollisionHandler.cs # Bot 碰撞管理 + 重生传送
│ ├── ClearCommands.cs # .clear / .break
│ ├── ConVarCommands.cs # .solid / .impacts / .traj
│ ├── DamageHandler.cs # 实时伤害提示
│ ├── DryRunCommands.cs # .dryrun / .restartround
│ ├── EventHandlers.cs # OnMapStart / OnEntitySpawned / EventPlayerBlind 等
│ ├── GrenadeCommands.cs # .rethrow* / .last
│ ├── GrenadeFunctions.cs # 投掷物生成辅助
│ ├── HelpCommand.cs # .help
│ ├── PracticeCommands.cs # .prac / .map
│ ├── ReplayCommands.cs # .record / .replay / .clearrecord* / .currentrecord
│ ├── SpawnCommands.cs # .spawn 系列 9 条
│ ├── SpawnMarkerCommands.cs # .showspawns / .hidespawns + E 键传送
│ ├── TeamCommands.cs # .watch / .fas
│ ├── TimeGodCommands.cs # .fastforward / .noflash / .god
│ └── TimerCommand.cs # .timer
├── cfg/PracLab/ # 服务器配置文件
│ ├── config.cfg # 插件总开关 + 默认语言
│ ├── prac.cfg # 练习模式 ConVar
│ └── dryrun.cfg # 竞技模式 ConVar
├── lang/ # 本地化
│ ├── zh-CN.json
│ └── en.json
├── replay-engine/ # Layer 2 C++ Metamod 插件
│ ├── src/ # 录制/回放/hook 实现
│ ├── include/praclab_replay.h # 跨语言 ABI 头文件
│ ├── configs/ # Metamod VDF + gamedata.json
│ ├── configure.ps1 # CMake 配置脚本
│ ├── build.ps1 # 编译脚本
│ └── CMakeLists.txt
└── documentation/ # 本文档(MkDocs)
├── docs/
└── mkdocs.yml
5. 跨语言 ABI 契约¶
Layer 1(C#)与 Layer 2(C++)之间通过 P/Invoke 调用 PRL_* 系列 C 函数通信。头文件位于 replay-engine/include/praclab_replay.h。
修改 ABI 时须同步更新两层代码:
| 修改类型 | Layer 1(C#) | Layer 2(C++) |
|---|---|---|
| 新增/修改结构体字段 | Commands/ReplayCommands.cs 中的 [StructLayout] 类 |
include/praclab_replay.h + src/exports.cpp |
| 新增导出函数 | Commands/ReplayCommands.cs 中的 [DllImport] 声明 |
include/praclab_replay.h 声明 + src/exports.cpp 实现 |
| 字段顺序调整 | 必须同步 | 必须同步(影响内存布局) |
6. 本地化文件维护¶
所有面向玩家的文本必须从 lang/*.json 加载:
lang/zh-CN.json— 中文(默认语言)lang/en.json— 英文