Compare commits

...

9 Commits

Author SHA1 Message Date
30390cb288 aot 泛型清单 2026-06-11 11:51:03 +08:00
d195bdd14e Add TH1 base engineering skill 2026-06-11 11:45:52 +08:00
972956323d Use AOT-safe MemoryPack config generation 2026-06-11 11:09:11 +08:00
75bbc0131e Fix AOT metadata loading for smoke builds 2026-06-11 02:46:07 +08:00
ac09170856 Add migration smoke build command 2026-06-11 02:08:26 +08:00
d0e23e6408 Fix hotfix AOT serialization entrypoints 2026-06-11 00:57:05 +08:00
0e3cb360ee 热更推进 2026-06-11 00:34:50 +08:00
8a19e4fe92 资源全部转AB 2026-06-10 11:58:18 +08:00
cd60cb26a0 热更clr进版 2026-06-09 20:49:52 +08:00
5097 changed files with 21421 additions and 51080 deletions

View File

@ -0,0 +1,175 @@
---
name: th1-base
description: TH1 project baseline engineering guide for Unity client changes: assembly boundaries, HybridCLR hotfix rules, YooAsset/AssetBundle resource rules, MemoryPack/AOT serialization safety, build packaging flow, and routing to domain skills. Use before broad TH1 Unity code/resource/build changes, especially when touching Scripts, asmdefs, HybridCLR, hotfix DLLs, StreamingAssets, BundleResources, Resources.Load replacement, YooAsset, MemoryPack, generated config, build panels, or package verification.
---
# TH1 Base Engineering
## Core Rule
Treat TH1 as a hot-update Unity project with a small AOT shell, a large `TH1.Hotfix` gameplay layer, and YooAsset-managed resources.
Most feature work may live in hotfix code, but platform bootstrap, HybridCLR/YooAsset initialization, AOT metadata loading, and build packaging must remain stable and boring. Do not solve a hotfix/AOT/resource issue with one-off special cases when a shared entrypoint or generator fix is possible.
## Skill Routing
Start here for baseline constraints, then add the domain skill that owns the behavior:
- `th1-ios-migration`: iOS/IL2CPP, HybridCLR, YooAsset, Steam platform isolation, touch/mobile, packaging.
- `th1-action-logic`: gameplay actions, AI action flow, turn state, replay, deterministic skill side effects.
- `th1-network-sync`: Steam lobby/P2P, GameStart/ForceUpdate, `MapData` network payloads, multiplayer resume.
- `th1-game-archive`: local save/load, `GameRecord`, archive files, resume, bug report archive payloads.
- `th1-multilingual`: localization export/import, `Multilingual.asset`, Workshop language mods.
- `th1-server-backend`: OSS/STS/function compute/upload/auth backend work.
- `th1-online-debug`: production logs, CrashSight/UnityLogError, obfuscated stack decode.
- `th1-crashsight-daily`: daily CrashSight triage and reports.
- `.agents/skills/th1-config-guide`: Excel config generation, `GenerateCS`/`ExcelPartial`, MemoryPack config rules.
- `.agents/skills/th1-ui-patterns`: View/Controller UI work.
- `.agents/skills/th1-ai-nodes`: NodeCanvas AI behavior tree nodes.
- `.agents/skills/th1-anim-scope`: attack animation scope-aware renderer updates.
If multiple skills apply, use this skill first, then the narrow domain skill.
## First Moves
- Run `git status --short`; preserve unrelated user/Unity changes.
- Identify whether the change touches AOT shell, hotfix code, resources/AB, serialization, build pipeline, platform services, or gameplay behavior.
- For Unity code changes, inspect nearby asmdefs and namespace ownership before moving files.
- For generated files, find and update the generator/template instead of hand-editing output, unless the user explicitly asks for a one-off generated output patch.
- Do not modify MemoryPack compatibility, obfuscation behavior, or generated config formats without explicit confirmation.
## Assembly Boundaries
Current target shape:
- AOT shell: minimal startup scene and bootstrap code. It loads AOT metadata, loads `TH1.Hotfix.dll.bytes`, initializes YooAsset, loads the game scene, then invokes hotfix entrypoints.
- `TH1.Hotfix`: gameplay logic, UI logic, renderer logic, config consumers, AI nodes, save/game/archive logic where possible.
- `TH1_Resource`: resource facade and compatibility wrappers. Gameplay code should load through these wrappers, not direct YooAsset calls scattered everywhere.
- Editor assemblies: build panels, HybridCLR/YooAsset tools, config/export windows. They must not leak into runtime/hotfix assemblies.
Rules:
- The Build Settings scene should be the empty/init AOT shell scene. The real game scene is loaded through YooAsset after hotfix and metadata are ready.
- Do not put hotfix `MonoBehaviour` references directly in the shell scene.
- If a prefab/scene contains hotfix scripts, it must be loaded only after the hotfix assembly is loaded.
- Keep startup contracts stable and explicit. Prefer direct typed calls for required runtime packages over reflection that silently skips failures.
- Hotfix code must not directly reference editor-only assemblies or platform-specific SDKs that are unavailable on the target platform.
## HybridCLR Rules
- After hotfix code, AOT dependency, or generic-heavy serialization changes, rerun the HybridCLR prepare flow before packaging.
- Required artifacts are platform-specific: hotfix DLL bytes and AOT metadata under `StreamingAssets/HybridCLR`.
- Load supplemental metadata before starting hotfix gameplay:
- `mscorlib.dll.bytes`
- `System.dll.bytes`
- `System.Core.dll.bytes`
- `MemoryPack.dll.bytes`
- `System.Runtime.CompilerServices.Unsafe.dll.bytes`
- Use `HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(..., HomologousImageMode.SuperSet)` for the required load path; do not hide missing RuntimeApi as a non-fatal reflection miss in player builds.
- Do not manually copy stale hotfix DLLs. Use the project build panel/command so generated DLL, AOT metadata, and build status stay consistent.
- If NodeCanvas/ParadoxNotion serialized task types are moved into hotfix, refresh/regenerate the relevant type metadata before packaging.
## MemoryPack And AOT Serialization
MemoryPack format compatibility is high risk. Preserve layout unless explicitly changing format.
Runtime/hotfix code should avoid direct generic MemoryPack entrypoints when the serialized type may live in hotfix:
```csharp
// Prefer project wrapper or Type API.
TH1Serialization.Serialize(value);
TH1Serialization.Deserialize<T>(bytes);
MemoryPackSerializer.Serialize(typeof(T), value);
MemoryPackSerializer.Deserialize(typeof(T), bytes);
```
Avoid adding new runtime code like:
```csharp
MemoryPackSerializer.Serialize<T>(value);
MemoryPackSerializer.Deserialize<T>(bytes);
```
Rules:
- Use `TH1_Logic.Tools.TH1Serialization` for gameplay/save/network/runtime data.
- For generators that cannot reference Unity runtime code, generate MemoryPack `Type` API calls.
- Do not reorder or remove existing `[MemoryPackInclude]` members in persisted/networked types. Append new fields.
- For old fields no longer used, keep compatibility placeholders when later fields would shift.
- Treat `MapData`, `NetData`, `GameRecord`, `GameRecordData`, config bytes, and network messages as compatibility-sensitive.
- If generated config code needs a change, update `ExcelExport/ExportTemplate_*.txt` and regenerate/sync output.
## YooAsset And AB Rules
Resources are moving to AB-first loading:
- Use `Assets/BundleResources` as the packaged resource root.
- Prefer stable logical addresses. Do not make gameplay code depend on platform-specific bundle paths.
- Replace `Resources.Load` through `TH1Resource.ResourceLoader`/resource cache wrappers, not scattered direct YooAsset calls.
- Editor may run simulate mode; PC/iOS packages should run actual built-in AB package logic.
- Rebuild YooAsset bundles after moving, adding, deleting, or renaming packaged assets.
- Keep Standalone and iOS bundles separate. Do not reuse PC bundle assumptions for iOS compression or platform output.
- Do not put invalid source files in AB roots: backups (`*.BAK`), raw local-only config, editor-only files, or unknown icon/temp files should live outside `BundleResources`.
- If an address is missing, fix the collector/address/generator path rather than adding local `Resources` fallbacks.
## Build And Packaging Flow
For migration-era PC IL2CPP smoke builds, use the project one-click flow where possible:
1. Configure target platform/build settings.
2. Configure HybridCLR.
3. Run HybridCLR `GenerateAll`.
4. Build hotfix DLL and copy hotfix/AOT metadata to `StreamingAssets`.
5. Build YooAsset built-in `DefaultPackage`.
6. Build Windows IL2CPP player.
7. Launch player and scan the log for startup red errors.
Manual Unity packaging gotchas:
- After scene list changes, use full `Build`/`Clean Build`; do not use `Build Scripts Only`.
- If you only need a runnable PC package, keep `Create Visual Studio Solution` off unless explicitly debugging the generated solution.
- Avoid `Script Debugging` for automated smoke player runs; it can wait for a managed debugger.
- If Unity exports a Visual Studio solution for IL2CPP, MSBuild may need current Windows SDK/toolset retargeting.
- Generated build artifacts such as `HybridCLRGenerate/AOTGenericReferences.cs` may change after HybridCLR GenerateAll; commit them only when intentionally refreshed.
- Obfuscator logs and local build output should not be committed unless explicitly part of the requested change.
Startup smoke success markers:
- AOT metadata logs show `OK`.
- `TH1.Hotfix` loads.
- YooAsset `DefaultPackage` initializes.
- Game scene loads from YooAsset.
- Hotfix `Main` starts.
- No `MissingMethodException`, `Type Request Error`, `NullReferenceException`, or `LogError` during startup.
## Verification
For ordinary Unity runtime C#:
```powershell
dotnet build Unity/Assembly-CSharp.csproj --no-restore
```
For editor/build/config tooling:
```powershell
dotnet build Unity/Assembly-CSharp-Editor.csproj --no-restore
```
Known caveat: this repo can hit Unity package compile errors outside changed code when building the full editor csproj from dotnet. If that happens, report it clearly and verify the narrower runtime/tool project or Unity Editor compile path instead.
For config generator changes:
```powershell
dotnet run --project ExcelExport/ExcelExport.csproj -- 1
dotnet build ExcelExport/ExcelExport.csproj --no-restore
```
Before finishing migration/build work, inspect:
```powershell
rg -n "Resources\\.Load|MemoryPackSerializer\\.Serialize<|MemoryPackSerializer\\.Deserialize<|using Steamworks|BuildScriptsOnly" Unity/Assets/Scripts
```
Only treat matches as problems after checking context; editor-only tools and intentionally platform-bound Steam implementations may be valid.

View File

@ -7,6 +7,7 @@ This repository is a Unity 2022.3 LTS / ET Framework turn-based strategy game. T
- For architecture questions, read the `MD/GameMDFramework/00-*` overview document and the relevant subsystem document before editing. - For architecture questions, read the `MD/GameMDFramework/00-*` overview document and the relevant subsystem document before editing.
- For code navigation, read `Unity/graphify-out/GRAPH_REPORT.md` for Unity code and `graphify-out/GRAPH_REPORT.md` for whole-repository context. - For code navigation, read `Unity/graphify-out/GRAPH_REPORT.md` for Unity code and `graphify-out/GRAPH_REPORT.md` for whole-repository context.
- If a task touches action execution, networking, localization, online errors, backend upload, or CrashSight reports, use the matching `.codex/skills/th1-*` skill first. - If a task touches action execution, networking, localization, online errors, backend upload, or CrashSight reports, use the matching `.codex/skills/th1-*` skill first.
- For broad TH1 Unity/code/resource/build changes, use `.codex/skills/th1-base` first, then layer the narrower business skill on top.
- Claude-era context remains in `.claude/` and `Unity/Assets/Scripts/CLAUDE.md`; treat it as historical source material, not the active entrypoint. - Claude-era context remains in `.claude/` and `Unity/Assets/Scripts/CLAUDE.md`; treat it as historical source material, not the active entrypoint.
## Project Shape ## Project Shape
@ -36,6 +37,7 @@ This repository is a Unity 2022.3 LTS / ET Framework turn-based strategy game. T
## Codex Skills And Agents ## Codex Skills And Agents
- Prefer `.codex/skills` for current project-specific workflows: - Prefer `.codex/skills` for current project-specific workflows:
- `th1-base`: baseline Unity engineering rules for assembly boundaries, HybridCLR hotfix, YooAsset/AB, MemoryPack/AOT serialization, generated config, and build/package verification.
- `th1-action-logic`: action execution, AI action flow, turn actions, and action-triggered skills. - `th1-action-logic`: action execution, AI action flow, turn actions, and action-triggered skills.
- `th1-network-sync`: Steam lobby, P2P, multiplayer save/recovery, action sync, and deterministic network behavior. - `th1-network-sync`: Steam lobby, P2P, multiplayer save/recovery, action sync, and deterministic network behavior.
- `th1-multilingual`: localization import/export, active text scanning, duplicate IDs, and translation diagnostics. - `th1-multilingual`: localization import/export, active text scanning, duplicate IDs, and translation diagnostics.

View File

@ -14,7 +14,7 @@ namespace ExcelConfig
public override void Init(byte[] data) public override void Init(byte[] data)
{ {
Dict = MemoryPackSerializer.Deserialize<Dictionary<int, (ConfigName)>>(data); Dict = (Dictionary<int, (ConfigName)>)MemoryPackSerializer.Deserialize(typeof(Dictionary<int, (ConfigName)>), data)!;
} }
} }

View File

@ -23,7 +23,7 @@ namespace ExcelConfig
public override byte[] GetData() public override byte[] GetData()
{ {
return MemoryPackSerializer.Serialize(Dict); return MemoryPackSerializer.Serialize(typeof(Dictionary<int, (ConfigName)>), Dict);
} }
} }

View File

@ -14,7 +14,7 @@ namespace ExcelConfig
public override void Init(byte[] data) public override void Init(byte[] data)
{ {
Dict = MemoryPackSerializer.Deserialize<Dictionary<int, AIConfig>>(data); Dict = (Dictionary<int, AIConfig>)MemoryPackSerializer.Deserialize(typeof(Dictionary<int, AIConfig>), data)!;
} }
} }

View File

@ -14,7 +14,7 @@ namespace ExcelConfig
public override void Init(byte[] data) public override void Init(byte[] data)
{ {
Dict = MemoryPackSerializer.Deserialize<Dictionary<int, GeoDesc>>(data); Dict = (Dictionary<int, GeoDesc>)MemoryPackSerializer.Deserialize(typeof(Dictionary<int, GeoDesc>), data)!;
} }
} }

View File

@ -14,7 +14,7 @@ namespace ExcelConfig
public override void Init(byte[] data) public override void Init(byte[] data)
{ {
Dict = MemoryPackSerializer.Deserialize<Dictionary<int, Moment>>(data); Dict = (Dictionary<int, Moment>)MemoryPackSerializer.Deserialize(typeof(Dictionary<int, Moment>), data)!;
} }
} }

View File

@ -23,7 +23,7 @@ namespace ExcelConfig
public override byte[] GetData() public override byte[] GetData()
{ {
return MemoryPackSerializer.Serialize(Dict); return MemoryPackSerializer.Serialize(typeof(Dictionary<int, AIConfig>), Dict);
} }
} }

View File

@ -23,7 +23,7 @@ namespace ExcelConfig
public override byte[] GetData() public override byte[] GetData()
{ {
return MemoryPackSerializer.Serialize(Dict); return MemoryPackSerializer.Serialize(typeof(Dictionary<int, GeoDesc>), Dict);
} }
} }

View File

@ -23,7 +23,7 @@ namespace ExcelConfig
public override byte[] GetData() public override byte[] GetData()
{ {
return MemoryPackSerializer.Serialize(Dict); return MemoryPackSerializer.Serialize(typeof(Dictionary<int, Moment>), Dict);
} }
} }

View File

@ -1,5 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 76014dabbf7df4d4b98dc8cbbae75ead guid: 17a20616b59b4a50aea9057818b224a5
folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@ -0,0 +1,49 @@
# HybridCLR Phase 1
## Scope
This phase only adds the hot-update foundation. It must not move turn actions, AI, network sync, MapData, replay, save compatibility, MemoryPack, Steam lobby/P2P, Workshop, or backend auth into hotfix assemblies.
## Added Layout
- `Assets/Scripts/TH1_Hotfix/TH1.Hotfix.asmdef`: first hot-update assembly.
- `Assets/Scripts/TH1_Hotfix/HotfixEntry.cs`: smoke-test hotfix entry.
- `Assets/Scripts/TH1_Logic/Hotfix/HotfixBootstrap.cs`: AOT-side loader.
- `Assets/Scripts/TH1_Logic/Editor/HybridCLR/TH1HybridCLRBuildTools.cs`: TH1 menu shortcuts.
Runtime artifact layout:
```text
Assets/StreamingAssets/HybridCLR/
HotfixDlls/
TH1.Hotfix.dll.bytes
AOTAssemblies/
mscorlib.dll.bytes
System.dll.bytes
System.Core.dll.bytes
```
The loader silently skips when `TH1.Hotfix.dll.bytes` is missing, so the Steam/editor flow can still run without any hotfix package.
## First Local Verification
1. Let Unity resolve `com.code-philosophy.hybridclr`.
2. Run `HybridCLR/Installer...`.
3. Run `Tools/TH1/iOS Migration/HybridCLR/2. Configure TH1 Hotfix Settings`.
4. Run `Tools/TH1/iOS Migration/HybridCLR/3. Generate All`.
5. Run `Tools/TH1/iOS Migration/HybridCLR/4. Compile Hotfix Dll`.
6. Run `Tools/TH1/iOS Migration/HybridCLR/5. Copy Hotfix Artifacts To StreamingAssets`.
7. Run `Tools/TH1/iOS Migration/HybridCLR/6. Test Load StreamingAssets Hotfix In Editor`.
Expected editor console smoke output:
```text
[TH1.Hotfix] Initialize version 0.1.0
[TH1.Hotfix] Loaded TH1.Hotfix, ...
```
## Next Boundaries
- Keep first hotfix content limited to UI presentation helpers, non-networked fixes, and feature flags.
- Do not add Steamworks references to `TH1.Hotfix`.
- Do not use hotfix as a way to bypass App Store review. Prefer resources/config for content updates and reserve code hotfix for cautious compatibility fixes.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4e3d91838fd2b974b80e6d441c8857b5 guid: 6b8e7fe2c7074d9e99bf77214afb1e74
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

File diff suppressed because one or more lines are too long

View File

@ -1,39 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 185f6993d5150494d98da50e26cb1c25, type: 3}
m_Name: AssetBundleCollectorSetting
m_EditorClassIdentifier:
ShowPackageView: 1
ShowEditorAlias: 1
UniqueBundleName: 1
Packages:
- PackageName: DefaultPackage
PackageDesc: "\u9ED8\u8BA4\u8D44\u6E90"
EnableAddressable: 0
LocationToLower: 0
IncludeAssetGUID: 0
AutoCollectShaders: 1
IgnoreRuleName: NormalIgnoreRule
Groups:
- GroupName: Default Group
GroupDesc: "\u9ED8\u8BA4\u5206\u7EC4"
AssetTags: "\u9ED8\u8BA4"
ActiveRuleName: EnableGroup
Collectors:
- CollectPath: Assets/LoadableResources
CollectorGUID: 6f361d8ecfc66184ca7316d96a6bb15e
CollectorType: 0
AddressRuleName: AddressByFileName
PackRuleName: PackDirectory
FilterRuleName: CollectAll
AssetTags:
UserData:

View File

@ -1,8 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: a60778dce43da574aa447ab3fcf5d9f7 guid: d54752b5ded74752932ba6970e4fda72
NativeFormatImporter: folderAsset: yes
DefaultImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 11400000
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More