feat(cordis): 接入上下文组合与模组事务热替换

This commit is contained in:
2026-08-16 23:20:40 +08:00
commit ad256f109b
676 changed files with 52168 additions and 0 deletions
@@ -0,0 +1,3 @@
bin/
obj/
artifacts/
@@ -0,0 +1,100 @@
# __PROJECT_NAME__
这是由 `ShrinkModFramework` 生成器创建的外部 DLL 模组模板。
## 模板内容
- `src/__PROJECT_NAME__Mod.cs`
- 模组主入口,演示 `ShrinkModFramework + ShrinkEventBus + ShrinkCommand + ShrinkNetwork`
- `src/__PROJECT_NAME__Contracts.cs`
- 示例事件、RPC 请求与响应
- `__PROJECT_NAME__.csproj`
- 独立类库工程,默认引用当前 SDK 仓库里的运行时工程
- `build.ps1`
- 一键构建,可选复制 DLL 到你的模组目录
- `dev-env.ps1`
- 先设置 `MSBuildEnableWorkloadResolver=false`,适合有些 IDE 打开项目前先跑一遍
- `global.json`
- 锁定到生成模板时检测到的 `dotnet SDK` 版本
## 默认标识
- `ProjectName`: `__PROJECT_NAME__`
- `Namespace`: `__ROOT_NAMESPACE__`
- `ModId`: `__MOD_ID__`
- `DisplayName`: `__DISPLAY_NAME__`
生成后建议你先改这几处,再开始写正式业务。
## 构建
```powershell
dotnet build .\__PROJECT_NAME__.csproj -c Release /nr:false
```
或者直接运行:
```powershell
.\build.ps1
```
如果你的 IDE 打开项目时报类似:
```text
Microsoft.NET.SDK.WorkloadAutoImportPropsLocator
```
先在 PowerShell 里执行:
```powershell
.\dev-env.ps1
```
然后在**同一个 shell** 里启动 IDE,或者直接继续 `dotnet build`。
默认产物输出到:
```text
artifacts\Release\
```
## 投放到游戏
`ShrinkModFramework` 当前会扫描:
```text
Application.persistentDataPath/Mods
```
所以常见流程是:
1. 先构建出 `__PROJECT_NAME__.dll`
2. 把 DLL 复制到游戏实际使用的 `Mods` 目录
3. 启动游戏,让 `ShrinkModLoader` 自动发现
如果你已经知道目标 `Mods` 目录,也可以直接用:
```powershell
.\build.ps1 -ModsDir "D:\YourGameMods\Mods"
```
## 这个模板示范了什么
- `[ShrinkMod]` 模组声明
- `ShrinkModBase` 生命周期
- `EventBusSubscriber` 实例自动接入
- `ShrinkCommandSubscriber` 实例命令自动接入
- `ShrinkNetworkSubscriber` 实例网络处理自动接入
- `context.GetRegistry(...)` 注册内容
- `context.RegisterNetworkHandler(...)` 走模组网络抽象层
## 注意
- 示例里用到的 `opcode`、命令路径、`modId` 都只是模板默认值,正式模组请自己调整,避免冲突
- 当前模板默认依赖当前仓库根目录下的:
- `ShrinkModFramework.Runtime.csproj`
- `ShrinkEventBus.Runtime.csproj`
- `ShrinkCommand.Runtime.csproj`
- `ShrinkNetwork.Runtime.csproj`
- 如果你把模板工程移到别处,需要同步修正 `__PROJECT_NAME__.csproj` 里的 `ProjectReference`
- 某些 IDE / MSBuild 环境里,`MSBuildEnableWorkloadResolver=false` 写在项目文件内仍然太晚;这种情况要靠 `dev-env.ps1` 或系统环境变量在**打开项目之前**先设置
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dfa94a3d7a41c6b4e81e7675db94e55f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
<RootNamespace>__ROOT_NAMESPACE__</RootNamespace>
<AssemblyName>__PROJECT_NAME__</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<EnableDefaultCompileItems>true</EnableDefaultCompileItems>
<OutputPath>artifacts\$(Configuration)\</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="__SDK_ROOT_RELATIVE__\ShrinkModFramework.Runtime.csproj" />
<ProjectReference Include="__SDK_ROOT_RELATIVE__\ShrinkEventBus.Runtime.csproj" />
<ProjectReference Include="__SDK_ROOT_RELATIVE__\ShrinkCommand.Runtime.csproj" />
<ProjectReference Include="__SDK_ROOT_RELATIVE__\ShrinkNetwork.Runtime.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 770057fe3b5782f4ba28e2e36f087b96
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,32 @@
param(
[string]$Configuration = "Release",
[string]$ModsDir = ""
)
$ErrorActionPreference = "Stop"
$projectPath = Join-Path $PSScriptRoot "__PROJECT_NAME__.csproj"
dotnet build $projectPath -c $Configuration /nr:false
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
$artifactDir = Join-Path $PSScriptRoot ("artifacts\" + $Configuration)
$dllPath = Join-Path $artifactDir "__PROJECT_NAME__.dll"
Write-Host "Build completed: $dllPath"
if ([string]::IsNullOrWhiteSpace($ModsDir)) {
return
}
New-Item -ItemType Directory -Force -Path $ModsDir | Out-Null
Copy-Item -LiteralPath $dllPath -Destination (Join-Path $ModsDir "__PROJECT_NAME__.dll") -Force
$pdbPath = Join-Path $artifactDir "__PROJECT_NAME__.pdb"
if (Test-Path -LiteralPath $pdbPath) {
Copy-Item -LiteralPath $pdbPath -Destination (Join-Path $ModsDir "__PROJECT_NAME__.pdb") -Force
}
Write-Host "Copied artifacts to: $ModsDir"
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 956930660ab00e74692b22857f3159b7
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
$env:MSBuildEnableWorkloadResolver = "false"
Write-Host "MSBuildEnableWorkloadResolver=false"
Write-Host "Current dotnet: $(dotnet --version)"
Write-Host ""
Write-Host "现在请在这个 PowerShell 里启动你的 IDE,或直接在这个 shell 里运行 dotnet build。"
Write-Host "示例:"
Write-Host " dotnet build .\\__PROJECT_NAME__.csproj -c Release /nr:false"
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 56c53370b8dbbab4ea70d4566bc1fed8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "__DOTNET_SDK_VERSION__",
"rollForward": "latestPatch"
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 48ebb276437630c4495d82c4c8e4ae2e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c8713158fd023ce48abfb7365184ac7c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
#nullable enable
using ShrinkEventBus;
using ShrinkNetwork;
namespace __ROOT_NAMESPACE__
{
public sealed class __PROJECT_NAME__Event : EventBase
{
public string Message { get; set; } = string.Empty;
}
[ShrinkNetworkMessage(__REQUEST_OPCODE__, "__ROUTE_PREFIX__/ping")]
public sealed class __PROJECT_NAME__PingRequest : IShrinkNetworkRequest
{
public string Message { get; set; } = string.Empty;
}
[ShrinkNetworkMessage(__RESPONSE_OPCODE__, "__ROUTE_PREFIX__/ping_response")]
public sealed class __PROJECT_NAME__PingResponse : ShrinkRpcResponseBase
{
public string Message { get; set; } = string.Empty;
public int Counter { get; set; }
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f4ff81758d9539947ba6f4df94c2db91
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,70 @@
#nullable enable
using ShrinkCommand;
using ShrinkEventBus;
using ShrinkModFramework;
using ShrinkNetwork;
namespace __ROOT_NAMESPACE__
{
[ShrinkMod("__MOD_ID__", "__DISPLAY_NAME__", "1.0.0")]
[EventBusSubscriber]
[ShrinkCommandSubscriber]
[ShrinkNetworkSubscriber]
public sealed class __PROJECT_NAME__Mod : ShrinkModBase
{
private readonly RuntimeState _state = new();
public override void OnConstruct(ShrinkModContext context)
{
context.Log("模组已构造。");
}
public override void OnRegisterContent(ShrinkModContext context)
{
var registry = context.GetRegistry<string>("example.items");
registry.Register(
context.ModInfo.ModId,
context.ModInfo.ModId + ":example_item",
"__DISPLAY_NAME__ Item");
}
public override void OnInitialize(ShrinkModContext context)
{
context.RegisterNetworkHandler<int>("sync.counter", (_, value) =>
{
_state.Counter = value;
context.Log("收到模组网络计数:" + value);
});
}
[EventSubscribe]
private void OnExampleEvent(__PROJECT_NAME__Event evt)
{
_state.LastEventMessage = evt.Message ?? string.Empty;
_state.Counter++;
}
[ShrinkCommand("__COMMAND_ROOT__ ping", Description = "测试模组命令", Permission = "__MOD_ID__.command.ping")]
private string Ping()
{
return "pong:" + _state.Counter;
}
[ShrinkNetworkSubscribe(Permission = "__MOD_ID__.rpc.ping")]
private __PROJECT_NAME__PingResponse HandlePing(__PROJECT_NAME__PingRequest request)
{
return new __PROJECT_NAME__PingResponse
{
Message = "pong:" + (request.Message ?? string.Empty),
Counter = _state.Counter
};
}
private sealed class RuntimeState
{
public int Counter { get; set; }
public string LastEventMessage { get; set; } = string.Empty;
}
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a2a0ac418f07ef74393b89e9612e3f5f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: