Current Unity architecture¶
Historical source snapshot: This page describes the project as inspected in October 2026; later player and ability migrations have changed parts of it. It is useful for tracing older startup, service and scene paths, but do not treat it as the current architecture. Use the playable-game roadmap, handoff and live source for current work.
Source-checked 2026-10-25. This describes existing ownership, not the target rebuild. The cleanup audit supplies whole-file coverage and target-boundary findings; the active plan owns dependency order.
Source layout¶
There are 227 C# files under Assets/Script, including eleven stabilization Editor check/audit files; vendored plugins and packages are outside this count.
| Folder | C# files | Responsibility and entry points |
|---|---|---|
Assets/Script/App |
54 | Boot, saves, settings, static application managers, menu controllers/views. |
Assets/Script/Game |
108 | Run orchestration, player/enemy logic, spawn events, rewards, upgrades, gameplay UI, and resources. |
Assets/Script/Shared |
15 | ScriptableObject definitions, interfaces, counters, session data. |
Assets/Script/TinyChaos |
22 | Data models, enums, file/JSON/encryption utilities, audio/save services. |
Assets/Script/External |
28 | Steam integration, leaderboard/network, tutorial, and Editor tools. |
Assets/Script/Core currently has no C# files. The old docs' Core/GameSystem folder plan does not describe the current layout.
SettingsInterface owns scene readiness, value display and balanced control listeners; GameSettings owns config/input operations and persistent applied graphics state. Model notifications refresh view state without persisting it. SwitchToggle explicitly synchronizes its presentation on silent value loading. MenuController restores parent focus and Page/TabsManager coordinate visible-page input. Batch 23 records these boundaries and the migrated scene data. Batch 24 replaces startup system overwrite with saved/fresh/session-override selection, awaited shared graphics application and observed applied state. SaveManager reports config origin without a new save field/schema. SplashUIController owns preload-ready versus activated handoff through one cached task. Remaining legacy routes and wider platform acceptance stay open.
Startup and scenes¶
The global build scene list starts with Bootloader, then MainMenu, three arena scenes, Tutorial, and Experimental. All seven entries are enabled. The Windows LZ4HC profile has m_OverrideGlobalSceneList: 0; its empty local scene array is not an empty build.
AppInitiator initializes input/localization and static managers, loads explicitly assigned game-data lists, then runs the startup flow: Steam identity, services, save/config startup, first settings application, MainMenu loading, and splash completion.
ServicesRoot (note the plural class name in a singular filename) creates AudioService and SaveService. SaveManager owns player/config data and publishes OnSaveReady. SplashUIController coordinates logos and scene/task completion. These are startup paths to inspect for GAME-01, not a proven explanation for the freeze.
Target ownership and staged fixture design are specified in the run/bootstrap contract. Its source wiring map is static evidence, not an implemented replacement or a player-build verification. Current runtime behavior below remains the baseline.
The player capability contract records planned motor/vitals/stats ownership and current numerical/ordering baselines. Its caller/serialized maps and source-derived cases do not establish runtime equivalence; no extraction is implemented by that design.
Run systems¶
| System | Existing source |
|---|---|
| Run coordinator | GameManager |
| Session flags/time-scale policy | GameStateService |
| Opt-in local lifecycle/operation traces | GameDiagnostics; collection and limits in runtime diagnostics |
| Gameplay initialization | GameInitializer.cs, whose declared MonoBehaviour is still GameInitialization |
| Progression | PlayerManager |
| Reward queue, cards, animations, rerolls | RewardRoller |
| Upgrade input/effects | UpgradeSelection, UpgradeFunction |
| Spawn director | SpawnerEventManager |
| Pooling | PoolManager |
| Data dictionaries/persistence bridge | GameDataLoader |
| Cross-run session | GameSession |
After batch 14, GameInitialization awaits reward reset, stage/spawn data, and scene-player setup, then yields GameManager.OpenGate to resume and start timers/HUD. Entry uses a separate opening transition without a scene-exit callback. Early Meadow gameplay is player-verified, and batch 15 additionally verifies repeated pause/resume with independent UI animation time. Batch 16 additionally verifies pause confirmations, a Meadow retry, and two arena returns using a complete independent-time closing sequence with transition ownership. Batch 20 additionally verifies game-over confirmation cancel/focus, retry, and MainMenu return. GameMenuManager owns result confirmation input/focus; Page disables both raycasts and keyboard interaction while hidden. Batch 21 verifies MainMenu quit/corner Exit and focus with actual quits on fresh/post-arena entries. MainMenuManager owns quit policy; MenuController emits page-pop notifications after parent restoration, replaces configured callbacks without losing observers, and no longer calls an empty MainMenu-specific view stub. Settings/Database/focus and later-stage serialization remain incomplete under GAME-24.
RewardUIController is still a placeholder. Its existence does not mean reward UI was extracted. GameManager and RewardRoller retain that responsibility. Flags and reward phase are separate. Batch 18 makes SetRewarding apply the existing time-scale policy, while the legacy GameManager.isPaused getter covers menu or reward pause. Its setter and GameState.IsPaused still own only menu pause; rerolls use that menu flag. Queued rewards wait behind menu pause. Game-over timing remains owned by its existing flow; this is not a general rewrite of all state transitions. See GAME-02 for verification limits rather than the archived completion claim.
Assets and production reachability¶
Runtime catalogs use explicitly assigned lists passed to GameDataLoader.Initialize; being inside Resources alone does not prove an asset is selectable. Scenes, prefabs, ScriptableObjects, and UnityEvent bindings are part of the implementation and must be checked alongside C#.
Assets/Scriptable Object, testing/development variants, and _Recovery scenes contain historical/prototype material. Do not delete them or promote them into production based solely on folder names. Establish reachability from the bootloader, catalogs, scenes, and reward tables first. Older detailed maps are in the archived Unity analysis.
Stage identity and progression¶
Batch 04 verified that AppInitiator.levels in Bootloader contains exactly Meadow, Crystal Mine, and Snowdrift Vale, in that order. MainMenu's three LevelSelectButton.levelData references point to these same assets. Resources Stage 4/5 are outside this boot catalog; their presence in a folder does not make them available through this selection path.
| Stage asset | Progression stageIndex |
sceneName for play/retry |
Persistent difficulty-ID prefix |
|---|---|---|---|
| Meadow | 1 | Arena Stage 1 |
1_ |
| Crystal Mine | 2 | Arena Stage 2 |
2_ |
| Snowdrift Vale | 3 | Arena Stage 3 |
3_ |
LevelData.stageIndex selects the one-based reward-stage flag; it is independent of the scene's position in the build list. LevelData.sceneName names the scene used by both MainMenu start and in-game retry. That scene must be enabled in the candidate's build list. The Experimental asset names its existing Experimental scene for retry, but remains outside the normal stage catalog; its release inclusion is still CONTENT-01.
GameManager.UnlockStage uses the current LevelData's position in the boot catalog to find a next stage. A Medium boss clear unlocks the current stage's Hard difficulty, its character reward if assigned, and the next stage's Easy/Medium if there is a next stage. Hard unlocks Insane; Insane unlocks Chaos. The final stage still grants its own difficulty/character rewards. No boss defeat means no progression changes. Meadow and Crystal Mine currently have no assigned character reward; that is permitted rather than a null-reference failure.
Persistent unlocks use StageMap.id through GameDataLoader.SaveResources, not the scene number. Preserve those IDs, stage names, asset GUIDs, and character IDs when correcting routing. The batch verified unlock calculations using cloned assets with save IO suppressed; persistence and complete scene transitions remain player-build checks. This establishes identity wiring, not a complete scene/HUD/spawner authoring guide.
Related existing systems¶
Related existing systems found during the owner's follow-up recollections:
| Area | Source and present boundary |
|---|---|
| Collection/database | CollectionManager, CollectionUIController, and CollectionView provide catalogs, selection routing, and character preview; enemy preview is a placeholder. See CONTENT-08 and IDEA-16. |
| Tutorial | TutorialManager owns lessons, actors and gate/scene progression. TutorialMenuController owns pause/menu and transition admission through the shared MenuController/Page stack; TutorialPlayer reads that owner for pause gates. Lesson completion/quality still needs acceptance; see IDEA-14. |
| Stage dialogue | DialogTrigger, DialogManager, and StageMap.dialog provide dialogue foundations. They do not establish a stage-comic system. See IDEA-15. |
| Leaderboard | LeaderboardManager handles HTTP/client records/cache/filters, with dedicated UI controller/view/button classes. Backend implementation is outside the inspected repository. See NET-01 and IDEA-12/13. |
The idea IDs above resolve in the design register, and issue IDs in the issue register.
Maintainability and authoring concerns¶
The owner remembers intertwined setup and large scripts as a major obstacle to returning to the project. The older analysis already describes these concerns; the table below reconnects them to the current Unity paths without adopting the cancelled rewrite's proposed architecture. ARCH-01 in the issue register tracks the overall concern. This map describes current coupling. Broad cleanup/rebuild is authorized; audit/contracts precede implementation, and each area migrates in dependency order rather than as a simultaneous rewrite.
| Area to understand | Current implementation and documentation gap |
|---|---|
| Player creation/setup | CharacterSelectionUIController chooses players/characters, GameSession carries the selection, and GameInitialization.PreparePlayer enables existing scene players, applies characters, and registers camera/HUD references. This is activation of wired scene objects, not a standalone player-spawning service. A complete authoring/setup checklist has not been reconstructed. |
| Control assignment | InputManager and GameSettings hold player-indexed keyboard/gamepad presets; Player reads from both input paths. The player/input contract records target ownership, existing bindings, migration consumers and behavior-preservation requirements. It is a design, not the implemented assignment model. IDEA-02's one-keyboard policy is approved for this rebuild. |
| Save/progression ownership | AppInitiator, ServicesRoot, SaveManager, SaveService, static Save, and data managers divide boot, IO, loading, and resource state. The maintenance reference maps current APIs/paths; SAVE issues track defects. A replacement save architecture is not chosen. |
| Audio/effect routing | ServicesRoot creates AudioService; AudioResources and AbilityResources hold references, while player/ability/UI code triggers playback/effects directly. Central service extraction did not eliminate cross-system coupling. A sound/skill wiring checklist remains to be reconstructed. |
| Enemy spawning | SpawnerData stores schedule entries and mutable event flags; GameInitialization assigns stage/difficulty schedules to SpawnerEventManager, which runs creep/special/boss flow using pooled prefabs. Existing prefab/state composition matters alongside C#. |
| Stage/scene authoring | LevelData ties stage availability/index, boss, music, and difficulty maps to schedules/dialog/duration; scene references and build inclusion are separate concerns. LevelManager, arena scenes, managers, camera/HUD wiring, and catalog registration must be traced together. The stage/enemy contract now specifies the planned shared-scene authoring recipe, current data/scene/state/event maps and migration checks. It is not yet an implemented or Unity-import-verified stage-building workflow. |
| Large mixed-responsibility scripts | GameManager, AbilityHolder, Player, Enemy, PlayerWeapon, PlayerAttack, and UpgradeFunction remain coupled. Some extraction exists (RewardRoller, PlayerManager, GameStateService), while RewardUIController is a placeholder. Class separation alone does not establish complete ownership separation. |
After batch 04, GameManager.cs has 774 lines, AbilityHolder.cs 1,512, Player.cs 960, and UpgradeFunction.cs 468. These dated counts help locate broad files; length alone is not a bug or a reason to rewrite them. The concern is that gameplay, state, UI, effects, and persistence cross their boundaries, making behavior harder to trace and change safely.
For each setup/authoring workflow, document its actual entry point, required data, component/asset wiring, runtime state owner, persistent state owner, and a way to verify it. Mark untraced steps explicitly. Do not fill the missing guide with an imagined new architecture. The archived redesign analysis and script inventory supply leads, not mandatory Unity implementation decisions.
Batch 33 records the proposed persistence/input preferences/UI/service integration contract with current saved-schema, legacy control, readiness, caller and adapter maps. Applying loaded audio/control/locale settings currently can persist config again; the target separates load/apply/edit/write ownership. Source event edges and optional-service payload limits are audited; profile recovery, remapping and adapter extraction remain unimplemented. See that contract for PS-01–PS-05 and the plan for the first R1 slice.
The opt-in rebuild runtime now includes RunSceneHost, RunSceneBindings and Gameplay.unity. These use batch 35's lifetime through explicit prepare/RunId-checked activation/stop; Awake does not start a run. The camera and empty environment stay inactive until accepted activation. Batch 36 records 7/7 import/PlayMode checks. Its Editor development window provides isolated Start/Stop/Reset; it is not in the scene's dependencies or production builds. Existing selection/GameManager/Player/input/stage/progression flows remain on their old owners. No player, enemy or real stage is present in this fixture.
The new opt-in input boundary is LocalPlayerRoster, LocalPlayerSlot and RosterRunParticipant. Batch 37 verifies simulated SDK ownership/identity and shared-host locking, with pinned Input System 1.17.0. The roster owns InputUsers rather than an actor-owned auto-pairing PlayerInput. Batch 38 adds GameplayPlayer.inputactions, PlayerInputSession, PlayerCommandFrame and SessionRunParticipant: per-player clones reuse those users, route Gameplay/Reward/Blocked commands, and retain run-stop/reconnect press barriers. Its 8/8 SDK groups use simulated devices. Raw movement still needs legacy-feel comparison; no new action source is connected to Player/AbilityHolder; AppInitiator/InputManager/current menus still use the old flow. Both input backends remain enabled. Native reconnection without serial needs explicit reassignment; existing recovery UI is not migrated.
Batch 39 adds InputBindingProfiles and LegacyInputProfileImport. They validate and edit a cloned config document in memory, retain legacy/unknown data, and create disabled per-profile action copies. Six preference profiles are not six active players. Nine Editor groups pass; normal loader/writer, live sessions and production actors are unmodified. See the profile boundary; the typed writer still drops the new section.
Batch 40 extends PlayerInputSession/InputBindingProfiles and adds InputBindingDraft: one blocked-session editing owner, immutable validated candidates, actual-session rollback, selected defaults and in-memory acceptance. It retains the existing action collection and InputUser. Nine new and eight prior simulated-device groups pass; current actors/menus/writers remain on their old paths. See the application contract.
Batch 41 adds InputBindingCapture under the draft owner. It collects only the existing device's supported control edges, then validates/previews after the SDK update, with release fencing, explicit cancel and ambiguity/conflict feedback. Ten new plus nine draft groups pass. It introduces no new input owner, view or writer; see the capture contract. The whole-config writer adapter precedes production remap persistence.
Batch 42 adds ConfigDocument, ConfigFileStore and the physical IO boundary. Full JSON owns unknown/input data while typed views prepare explicit patches; one store owns staged writes, byte conflicts, verified recovery originals and uncertain outcomes. Ten disposable Linux-file groups pass. Production SaveManager/SaveService/GameSettings are unmodified; compatibility/load-apply-save handoff precedes routing, and Windows/recovery/retention remain gates. See the config boundary.
Batch 43 extends ConfigDocument with explicit compatibility preset commands and separates GameSettings saved-preset application from saving UI edits. A shared validated preset plan retains the existing role assets and public controls. Ten new actual-method/disposable-file groups and ten existing persistence groups pass. The production typed writer, audio/locale startup save calls and wider owner handoff remain unmigrated; no actor/input polling migration or gameplay rule change.
Batch 44 separates loaded audio and locale application from saving commands. GameSettings explicitly persists a changed first-run screen choice instead of relying on audio setters. Locale application releases its busy flag on error/disposal and repeated initialization retains one load callback. Eight new method/SDK-fixture groups and seven existing settings-screen groups pass. This does not replace the typed config writer, redesign audio playback/CoroutineRunner or verify full startup/catalog rendering; production config-owner integration is next.
Batch 45 adds ConfigSettingsOwner, now called by SaveManager's production config load/save boundary. It bridges the mutable legacy view into full-document patches, owns pending edits and explicit preset intent, and pins the already-resolved path. Bootloader supplies the existing action definition; generic config writes reject. Ten new plus 34 regression groups pass with disposable Linux Editor IO. Player/progression bodies are unchanged. Full startup/player, recovery UI/retention/stale locks and Windows acceptance remain pending; production input still uses legacy polling.
Batch 46 adds native Linux IL2CPP evidence without changing implementation: actual scalar edit/backup/quit/restart and read-only loaded Settings, plus scoped current/legacy/rejected-file startup probes. This does not integrate remap capture/draft output into the owner; that explicit input commit command is next before setup/remap UI. Player/AbilityHolder, released stages and legacy polling are unchanged.