16 KiB
name, description
| name | description |
|---|---|
| th1-ios-migration | TH1 project-specific iOS migration guide for same-mainline dual-platform support: HybridCLR hot update foundation, iOS/IL2CPP compile isolation, Steamworks/Steam SDK platform abstraction without Steam regressions, touch input adaptation, YooAsset AssetBundle/resource migration, BundleResources DataAssets -> Export packaging sync, iOS build settings, unified PC/iOS build window flow, and verification that existing online Steam builds and gameplay behavior remain unaffected. Use whenever Codex works on TH1 iOS packaging, mobile porting, HybridCLR, YooAsset AB/resource loading, removing direct Steamworks references for iOS, platform services, touch controls, or build pipeline changes that must preserve the current Steam version. |
TH1 iOS Migration
Core Rule
TH1 iOS migration is same-mainline dual-platform work. Do not create a long-lived Steam code line and a separate mobile code line.
Every change must preserve the existing Steam build and gameplay behavior while adding iOS support through platform-specific implementations, build defines, asmdef/platform settings, and no-op/mobile services.
Default target shape:
- Shared gameplay, action logic, AI,
MapData, config, save data, and localization stay common. - Steam SDK, Steam lobby/P2P, Workshop, Steam auth, and Steam-specific UI live behind Steam-only platform boundaries.
- iOS gets IL2CPP/AOT-compatible code, mobile/no-op platform services, touch input, and platform-specific resources.
- Steam and iOS may have separate build profiles, resource bundles, and release branches, but not divergent business logic.
First Reads
Read the relevant files before editing:
MD/GameMDFramework/00-主文档-游戏架构总览.mdMD/GameMDFramework/11-网络与Steam.mdMD/GameMDFramework/13-配置与数据资产.mdUnity/Packages/manifest.jsonUnity/ProjectSettings/ProjectSettings.assetUnity/Assets/Scripts/TH1_Logic/Core/Main.csUnity/Assets/Scripts/TH1_Logic/Net/ILobby.csUnity/Assets/Scripts/TH1_Logic/Net/LobbyManager.csUnity/Assets/Scripts/TH1_Logic/Steam/SteamLobbyManager.csUnity/Assets/com.rlabrecque.steamworks.net/Runtime/com.rlabrecque.steamworks.net.asmdefUnity/Assets/Scripts/TH1_Logic/Input/InputLogic.csUnity/Assets/Scripts/TH1_UI/CameraController.csUnity/Assets/Scripts/TH1_UI/View/Base/View.csUnity/Assets/Scripts/TH1_Logic/Rersource/ResourceManager.csUnity/Assets/AssetBundleCollectorSetting.assetUnity/Assets/Scripts/TH1_Resource/ResourceCache.csUnity/Assets/Scripts/TH1_Logic/Config/ConfigManager.cs
Also use:
th1-network-syncwhen touching lobby, P2P,GameNetSender,GameNetReceiver,NetData, action sync, reconnect, or multiplayer start/resume.th1-action-logicwhen changing authoritative gameplay, action execution, AI action flow, replay, or deterministic behavior.th1-multilingualwhen changing Workshop/local mod language loading or localization resources.th1-server-backendwhen replacing Steam auth, STS, OSS upload, bug report upload, or backend identity.
Migration Order
Use this order unless the user explicitly changes it:
- Add HybridCLR foundation.
- Clean iOS compile isolation and Steam platform boundaries.
- Add touch/mobile input adaptation.
- Migrate resources to YooAsset AssetBundle flow.
- Add automated Steam/iOS build and hot-update packaging verification.
Do not use AB/YooAsset migration as a way to hide platform compile errors. iOS compile isolation must become clean before large resource replacement.
Phase 0: Baseline And Steam Parity Contract
Before editing:
- Run
git status --shortand preserve unrelated user changes. - Search direct platform dependencies with
rg -n "using Steamworks|SteamUser|SteamFriends|SteamUtils|SteamUGC|SteamAPI|SteamManager|TH1_Logic\\.Steam|UNITY_IOS|STEAM_CHANNEL|Resources\\.Load|Input\\.Get|mousePosition|safeArea" Unity/Assets/Scripts. - Identify whether the change is platform boundary, hotfix assembly layout, touch input, resource loading, backend auth, or build settings.
- Write down which Steam behavior must remain identical: lobby, P2P, Workshop, achievements, bug report upload, OSS collect upload, config/save, UI visibility, and multiplayer action sync.
Steam parity rules:
- Do not delete Steamworks.NET or Steam-specific scripts as part of iOS migration.
- Do not remove
STEAM_CHANNELbehavior for Standalone. - Do not change multiplayer state machines unless the task is explicitly network work and
th1-network-syncis active. - Do not move authoritative action logic into hotfix assemblies unless the user explicitly accepts the extra deterministic and replay risk.
- Do not modify obfuscation, MemoryPack compatibility, or generated config outputs without repeated explicit confirmation from the user.
Phase 1: HybridCLR Foundation
Goal: create a hot-update pipeline without changing Steam gameplay.
Preferred first scope:
- Add HybridCLR package/config/build steps.
- Run the HybridCLR Installer before
GenerateAllon any fresh machine, package re-resolution, or HybridCLR package update. In TH1 useTools/TH1/iOS Migration/HybridCLR/1. Run HybridCLR Installer, then clickInstall. - Create hotfix assembly boundaries such as
TH1.Hotfixonly after deciding what belongs there. - Keep authoritative turn/action/AI/network contracts in AOT main assemblies at first.
- Put low-risk UI, presentation helpers, non-networked bug fixes, or feature flags into hotfix first.
- Generate and commit required AOT metadata/link preservation files only through the documented HybridCLR workflow.
- Ensure the Steam build can still run without downloading any hotfix package when using local/editor mode.
iOS constraints:
- iOS is IL2CPP/AOT. Assume reflection, generic sharing, MemoryPack formatters, and dynamically referenced types can be stripped unless preserved.
- Treat code hot update on iOS as sensitive. Do not present it as a way to bypass App Store review. Prefer resources/configs for content updates and use code hotfix cautiously.
- Keep a rollback path: base app version, hotfix manifest version, minimum compatible app version, and ability to ignore bad hotfix packages.
Checks:
- Steam Standalone compile still succeeds.
- iOS IL2CPP compile reaches the next real blocker.
- Hotfix assembly does not reference Steamworks or editor-only assemblies.
link.xml/preserve additions are minimal and justified.HybridCLRData/AssembliesPostIl2CppStrip/<BuildTarget>exists after Generate All, and required AOT metadata has been copied toAssets/StreamingAssets/HybridCLR/AOTAssemblies.- If
HybridCLR/Generate/Allfailed because HybridCLR was not installed, do not continue into AB packaging. Fix the installer/generate step first.
Phase 2: iOS Compile Isolation And Steam Boundary
Goal: iOS compiles without Steamworks types while Steam keeps full behavior.
Preferred pattern:
- Move platform-neutral DTOs out of
TH1_Logic.SteamintoTH1_Logic.Netor a platform-neutral namespace before sharing them throughILobby. - Make
ILobbyand shared UI/data contracts free ofSteamworkstypes. - Keep
SteamLobbyManager,SimpleP2P,GameNetSender,GameNetReceiver, Workshop browser/uploader, and Steam auth under Steam-only compile/platform boundaries. - Add mobile/no-op implementations for services iOS cannot use yet.
- Hide or disable unsupported iOS UI entries instead of leaving clickable failing paths.
Use platform services for direct SDK access:
IPlatformUser: user id, display name, login state.IPlatformLobby/existingILobby: lobby/multiplayer operations.IPlatformAchievement: local/Steam/Game Center achievements.IPlatformWorkshopor local mod service: Workshop and local mod separation.IPlatformAuth: Steam ticket, Game Center/apple/backend/anonymous auth.IPlatformBackendUpload: OSS/bug report/collect upload routing.
Compile guard guidance:
- Prefer asmdef include platforms and service implementations over scattered
#if. - Use
#if STEAM_CHANNEL || UNITY_STANDALONEonly around Steam-specific code, not around shared gameplay. - Do not make
UNITY_EDITORautomatically mean Steam behavior if that blocks iOS simulation or mobile service testing in editor. - Keep editor-only tooling under editor asmdefs or
#if UNITY_EDITOR.
Checks:
rg -n "using Steamworks|SteamUser|SteamFriends|SteamUtils|SteamUGC|SteamAPI|SteamManager" Unity/Assets/Scripts -g '!Steamworks.NET/**'should show only Steam-only files or files guarded out of iOS.LobbyManagerselects Steam for Steam builds and no-op/mobile for iOS.- iOS build does not compile against the Steamworks.NET asmdef.
- Steam multiplayer, Workshop, and Steam upload paths are unchanged or covered by explicit parity tests.
Phase 3: Touch And Mobile Input
Goal: single-player iOS is playable without keyboard/mouse.
Touch work is a UX layer, not a gameplay mutation layer:
- Do not bypass action construction or
CheckCan/CompleteExecute. - Convert tap/drag/pinch/cancel/confirm into the same input/action intentions used by existing UI and
InputLogic. - Keep keyboard/mouse shortcuts working on Steam.
- Add touch-specific affordances when keyboard shortcuts previously exposed required commands.
Minimum iOS control coverage:
- Tap grid/unit/city selection.
- Tap action buttons and confirm/cancel flows.
- Drag camera.
- Pinch zoom replacing mouse wheel.
- Long press or explicit UI button for right-click/cancel-equivalent actions.
- Safe area handling for top/bottom UI.
- ScrollRect feel and button target size on touch.
Checks:
- Single-player start, select civ/force, generate map, move unit, attack, build/train, end turn, save/load, and finish game remain possible on touch.
- Steam keyboard/mouse behavior is not removed.
- UI text and buttons fit common iPhone and iPad aspect ratios.
Phase 4: YooAsset AssetBundle Flow
Goal: move toward AB/resource hot update without destabilizing the Steam build.
Use the existing YooAsset package and AssetBundleCollectorSetting.asset unless there is a clear reason not to.
Current TH1 built-in resource shape:
- Packaged resource root is
Assets/BundleResources. TH1YooAssetBuildTools.ConfigureDefaultPackageCollector()should collect the whole root for the default package.TH1AddressByBundleResourcesPathstripsAssets/BundleResources/, soAssets/BundleResources/Export/Multilingual.assetbecomes addressExport/Multilingual.asset.TH1Resource.ResourceLoader.Load<T>("Export/VersionConfig")and similar calls normalize addresses and try extension candidates. Do not change runtime callers to platform-specific paths when the collector/address rule is the real issue.- Runtime config/localization/table data usually reads
Export/...; rawDataAssets/...is the authoring source copied/transformed by the multilingual export/import flow.
Recommended sequence:
- Finish a real
ResourceManagerwrapper around YooAsset package initialization. - Start with
OfflinePlayModeso resources are packaged with the app. - Add platform-specific package build output: Standalone and iOS must produce separate bundles.
- Move high-value resource groups first: UI prefabs, common sprites, audio, config data assets, large visual assets.
- Replace
Resources.Loadthrough local resource/cache entrypoints, not scattered direct YooAsset calls. - Only after Offline is stable, add
HostPlayModefor CDN/OSS remote resource update.
Resource rules:
- Keep stable logical addresses. Do not make gameplay code depend on platform-specific paths.
- Do not modify export-flow outputs such as
Unity/Assets/BundleResources/Export/*,Tools/Multilingual.xlsx, orTools/MultilingualTxt.txtunless the user asked for export/import changes. - In the current migration, export-flow outputs live under
Assets/BundleResources/Export/*. If a package shows the wrong version, stale text, or stale table config, first check whetherDataAssets -> Exportwas refreshed before AB build. - Before a release/debug package, run or explicitly skip with confirmation the multilingual export/import flow (
Tools/一键导出导回or the checkbox inTH1UnifiedBuildWindow). It refreshesExport/*,Multilingual.asset, Excel/TXT intermediate files, andMatchLevelData/ExportLevelData.bytes. - Use iOS-specific texture/audio compression settings and bundle output. Do not reuse PC texture assumptions blindly.
- Treat generated config/DataAsset loading as compatibility-sensitive; preserve existing table and localization behavior.
- For Unity 2021+ / Unity 2022 with YooAsset 2.1.1, prefer SBP (
ScriptableBuildPipeline) for built-in package builds. YooAsset's BBP path uses Unity's oldBuildPipeline.BuildAssetBundlescall and can trigger the internal assertionm_InstanceIDToAssetBundleIndex.count(id) > 0. - YooAsset 2.1.1 SBP does not support
ForceRebuild; useIncrementalBuildand keepBuildinFileCopyOption = ClearAndCopyAllwhen building TH1 built-in packages. - Switching BBP to SBP is not a fix for missing HybridCLR AOT metadata. Diagnose HybridCLR installer/generate failures separately.
- Do not mix BBP and SBP outputs within one remote patch diff chain. Treat a pipeline switch as a full new package baseline and verify resource loading before release.
Checks:
- Steam package can still load existing resources in editor and standalone.
- iOS package uses iOS bundles and does not load PC-only bundle variants.
- Missing asset failures are logged with package/address/platform.
- No synchronous remote download is required during deterministic action execution.
- After a BBP/SBP pipeline change, smoke-test main menu, config loading, UI opening, entering a game, map/unit rendering, and audio/effect loading.
Phase 5: Build Pipeline And Release Discipline
Maintain one main branch with separate build profiles:
- Steam build: Standalone,
STEAM_CHANNEL, Steamworks.NET, Steam lobby/P2P, Workshop, Steam auth/upload. - iOS build: iOS, IL2CPP, mobile platform services, no Steamworks compile dependency, touch enabled, iOS bundles.
- Hot update build: platform-specific HybridCLR DLL/AOT metadata and YooAsset manifests.
Prefer Tools/TH1/一体化出包工具 for manual PC/iOS packaging. The one-click path should be staged and stop on first failure:
- Apply version/platform/package defines and OPS obfuscation target.
- Optional but recommended multilingual export/import (
DataAssets -> Export). - Configure HybridCLR.
- Configure YooAsset collector.
- HybridCLR
GenerateAll. - Build hotfix DLL/AOT metadata.
- Build YooAsset built-in AB.
- Check build blockers.
- Build Player.
The confirmation dialog should show the selected version and whether the multilingual export/import step is enabled.
Release branches may exist for stabilization only:
release/steam-*andrelease/ios-*may freeze and cherry-pick fixes.- All durable business logic fixes should return to the shared mainline.
- Avoid copy-pasted Steam/mobile variants of gameplay classes.
Verification
For ordinary C# changes run:
dotnet build Unity/Assembly-CSharp.csproj --no-restore
For editor/build pipeline/resource tooling changes also run:
dotnet build Unity/Assembly-CSharp-Editor.csproj --no-restore
Also verify the relevant Unity builds when possible:
- Steam Editor/Standalone smoke test.
- iOS switch-platform compile or Xcode export.
- HybridCLR generate/compile hotfix artifacts.
- YooAsset build for the touched package/platform.
Manual smoke checklist:
- Steam: start game, create/join lobby if network touched, Workshop/mod page if Workshop touched, bug report/upload if backend touched.
- iOS/mobile: launch, start single-player, touch select/move/action/end turn, save/load, rotate/aspect/safe area check.
- Shared: config load/save, localization, achievements/local progress, no hardcoded game-facing text added.
Stop Conditions
Stop and ask before continuing if:
- A change would require editing MemoryPack serialization compatibility, obfuscation config, generated config outputs, or Steam backend auth contracts.
- The only easy path is duplicating gameplay code between Steam and iOS.
- iOS support would require removing or weakening existing Steam multiplayer guarantees.
- A hotfix assembly needs to own authoritative action/network/replay logic before the migration baseline is stable.