# STEP A — PROJECT ANALYSIS REPORT ## Deviant Mobile — Senior Unity Mobile Optimization Audit --- ## 1. PROJECT OVERVIEW | Metric | Value | |--------|-------| | **Engine** | Unity 6 (URP 17.3.0) | | **Platform** | Android (arm64-v8a) / iOS 15+ | | **Genre** | 3v3 Fighting Game | | **Game Modes** | Cash System (objective-based), Practice (deathmatch) | | **Characters** | 6: Windham (Rabbit), Amira (Cheetah), Bahman (Eagle), Ziggy (Cat), Amon (Hammerhead), Imani (Hyena) | | **C# Scripts** | 202 | | **Prefabs** | 191 | | **Materials** | 371 | | **FBX Models** | 328 | | **Shaders** | 42 | | **Animation Files** | 3 (.anim) + 17 Animator Controllers in Resources | | **Scene Files** | 154 total (80 recovery duplicates, 2 main) | | **Total Assets Folder** | **28 GB** | | **DEVIS (art source)** | **26 GB** (92.8% of project) | | **Resources Folder** | 1.7 MB (6 character prefabs, 2 bags, 1 cash box, 17 animator controllers) | --- ## 2. ARCHITECTURE MAP ``` ┌─────────────────────────────────────────────────────────────────────┐ │ SCENE: Main Menu │ │ ┌─────────────┐ ┌──────────────────┐ ┌──────────────────────┐ │ │ │ GameManager │ │ SelectionOptions │ │ CharacterPrefabMgr │ │ │ │ (Singleton) │ │ (DontDestroy) │ │ (DontDestroy) │ │ │ │ Mode/Audio │ │ Team data+sprites│ │ Name→Prefab path map │ │ │ └──────┬───────┘ └────────┬─────────┘ └──────────┬───────────┘ │ │ │ │ │ │ │ ┌──────┴──────────────────┴────────────────────────┴───────────┐ │ │ │ CharacterSelection / ModeSelection │ │ │ │ CashSystemCharacterSelection │ │ │ └───────────────────────────┬───────────────────────────────────┘ │ └──────────────────────────────┼──────────────────────────────────────┘ │ LoadScene("Game") ┌──────────────────────────────┼──────────────────────────────────────┐ │ SCENE: Game │ │ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ CORE INFRASTRUCTURE │ │ │ │ ┌─────────────┐ ┌──────────┐ ┌───────────────────────┐ │ │ │ │ │ GameEvents │ │ObjectPool│ │ EntityRegistry │ │ │ │ │ │ 25 static │ │ Queue │ │ Static per-type lists │ │ │ │ │ │ Action │ │ Generic │ │ FindNearest/Radius │ │ │ │ │ └──────────────┘ └──────────┘ └───────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────┐ ┌────────────────────────────────┐ │ │ │ CashSystemManager │────▶│ CashBagSpawner (ObjectPool) │ │ │ │ (Singleton, 1349L) │ │ CashBag (state machine) │ │ │ │ Timer, Spawning, │ │ CashCarrier (per-character) │ │ │ │ Switching, Win │ │ TeamVault (deposit/steal zone) │ │ │ │ BuzzerBeater │ │ CashBoxImportController │ │ │ └──────────┬──────────┘ └────────────────────────────────┘ │ │ │ │ │ ┌──────────┴──────────────────────────────────────────────────┐ │ │ │ CHARACTER LAYER (×6) │ │ │ │ ┌─────────────────┐ ┌──────────────────────┐ │ │ │ │ │ Player-Controlled│ │ AI-Controlled (×5) │ │ │ │ │ │ CharacterInput │ │ CharacterAIController│ │ │ │ │ │ CharacterMovement│ │ + CashSystemAI │ │ │ │ │ │ PlayerController │ │ + AIBrain (new) │ │ │ │ │ └────────┬─────────┘ └──────────┬───────────┘ │ │ │ │ │ │ │ │ │ │ ┌────────┴────────────────────────┴──────────────────┐ │ │ │ │ │ SHARED COMPONENTS │ │ │ │ │ │ HealthNew (1259L!) │ StaminaSystem │ │ │ │ │ │ CharacterMovement │ AnimationManager │ │ │ │ │ │ TeamMember │ CashCarrier │ │ │ │ │ │ EnemyTargetDetector │ FaceTargetOnAttack │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ UI LAYER │ │ │ │ ┌────────────┐ ┌────────────┐ ┌───────────────────┐ │ │ │ │ │CashSystemUI│ │TeamHUDPanel│ │ Minimap System │ │ │ │ │ │ Timer,Vault│ │ Portraits │ │ MinimapManager │ │ │ │ │ │ KillFeed │ │ Health Dial│ │ MinimapMarker(s) │ │ │ │ │ │ Combo,Warn │ │ Switch tap │ │ EdgeIndicator │ │ │ │ │ └────────────┘ └────────────┘ └───────────────────┘ │ │ │ │ ┌────────────────┐ ┌─────────────────────┐ │ │ │ │ │ PreMatchIntroUI │ │ MatchResultUI │ │ │ │ │ │ 3v3 splash │ │ VICTORY/DEFEAT │ │ │ │ │ │ Countdown │ │ per-mode stats │ │ │ │ │ └────────────────┘ └─────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────┐ ┌────────────────────────────────────┐ │ │ │ Camera System │ │ Save System │ │ │ │ CameraFollow │ │ SaveManager (DontDestroy) │ │ │ │ CinemachineInput │ │ JsonDataService (XOR "encrypt") │ │ │ │ CameraShake │ │ GameData (wins/losses/rank/XP) │ │ │ └─────────────────────┘ └────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Asset Loading (Custom) │ │ │ │ RemoteAssetBundleManager → JSON catalog → bundle download │ │ │ │ AssetBundleDownloadManager → loading screen progress │ │ │ │ CustomAssetBundleSceneLoader → scene loader │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌───────────────────────────────────────┐ │ │ │ DISABLED: SpecialMoveCardSystem │ │ │ │ (CARD_SYSTEM_DISABLED = true) │ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 3. SYSTEM-BY-SYSTEM ANALYSIS ### 3.1 MOVEMENT & AI SYSTEM #### CharacterAIController (931 lines) - **Pattern:** Coroutine-based decision loop (0.3s tick, 0.8s far tick) — good AI LOD - **Strengths:** Distance-based decision throttling, NavMeshAgent-based, Camera.main cached at Awake - **Concerns:** - `FixedUpdate()` runs scale protection (`transform.localScale != originalScale`) every physics tick on every AI — workaround for FBX baked curves that should be fixed at import - `cachedPlayerManager` declared but potentially never populated #### EnemyAIController (270 lines) + TeamAIController (266 lines) - **Pattern:** Separate coroutine-based controllers for enemy/ally AI - **CRITICAL:** These appear **redundant** with `CharacterAIController` — three separate AI controller classes handling overlapping roles = maintenance nightmare - **Concerns:** `Debug.Log` on every `OnEnable`/`OnDisable` — string allocation in production #### CashSystemAI (741 lines) - **Pattern:** Weighted utility scorer with AI roles (Balanced, Collector, Defender, Aggressor) - **CRITICAL:** Coexists with `AIBrain` — the newer replacement system. Both gate on `isCashSystemSelected`. Unclear which is active at runtime. - **Strengths:** 0.3s decision interval, state minimum duration preventing thrashing #### AIBrain (353 lines) — NEW SYSTEM - **Pattern:** Modular AI with `UtilityScorer`, `AIBlackboard`, `AIPerceptionSystem`, `AINavigationHelper` - **Strengths:** 3-tier distance-based LOD ticking (0.3s / 0.5s / 1.0s), zero `FindObjectOfType`, pluggable actions - **Concern:** Coexists with legacy `CashSystemAI` — migration incomplete #### AIPerceptionSystem (242 lines) - **Pattern:** Zero-alloc detection via `Physics.OverlapSphereNonAlloc`, memory system with `_lastKnownPositions` - **Strengths:** Static shared collider buffer (safe in single-threaded Unity), FOV-filtered - **Concern:** Static `Collider[32]` buffer — size is fine for 3v3 but architecture couples all instances #### CharacterMovement (582 lines) - **CRITICAL BUG:** Heavy use of **static fields** (`jump`, `jumpForce`, `gravity`, `isSprinting`, `turnSpeed`, `targetDirection`) — ALL CharacterMovement instances share the same values. Setting gravity for one character changes it for all 6. This is a **game-breaking bug** in 3v3 mode. - **Concern:** Multiple `Debug.Log` including input values that could fire per-frame - **Concern:** Dual input paths (legacy `PlayerScript` + new `CharacterInputHandler`) adds complexity ### 3.2 CASH SYSTEM #### CashSystemManager (1349 lines) — GOD CLASS - **CRITICAL:** `Update()` fires `GameEvents.FireTimerUpdated(matchTimer)` **EVERY FRAME**. All UI subscribers process this every frame. Should throttle to ~4Hz. - **Concern:** 1349 lines handling spawning, timer, switching, win conditions, buzzer mechanic — massive SRP violation - **Concern:** `Start()` creates multiple manager singletons via `new GameObject()` + `AddComponent()` — fragile order-dependent init - **Concern:** 20+ `Debug.Log` calls with string interpolation #### CashBagSpawner (345 lines) — CLEAN - **Strengths:** Uses `ObjectPool` for zero-runtime allocation spawning, coroutine-based waves, `EntityRegistry` for distance checks - **One of the cleanest classes in the codebase** #### CashBag (416 lines) - **Concern:** `Update()` runs idle animation (rotation+bobbing) every frame on every active bag (up to 15). Could use coroutine or be batched by spawner. - **Concern:** Drop despawn timer uses per-frame deltaTime accumulation — coroutine would be cleaner #### CashCarrier (375 lines) - **Concern:** Dual cash tracking (`_legacyCash` float + `_carriedBags` list) — legacy compatibility dead weight #### TeamVault (357 lines) - **Strengths:** Coroutine-based magnet pulse (0.3s interval), event-driven deposit/steal notifications - **No issues:** Clean implementation #### CashBoxImportController (680 lines) - **Concern:** 680 lines for an import animation — camera manipulation (reparenting, position override) is fragile and could conflict with CinemachineFollow ### 3.3 UI SYSTEM #### CashSystemUI (643 lines) - **Strengths:** Fully event-driven (14 GameEvents subscriptions), no polling, `_dirtyVault` flag for efficient LateUpdate - **Concern:** 643 lines with 14+ event handlers — could be decomposed into TimerUI, ScoreUI, KillFeedUI, etc. #### TeamHUDPanel (365 lines) - **Concern:** Parallel list pattern (6 separate lists indexed together: portraits, health dials, backgrounds, name labels, dead overlays, highlight borders) — fragile. Should be a `TeamSlot` struct/class array. - **Concern:** Likely Updates health dials per-frame on all team members — should be event-driven on `OnHealthChanged` #### MatchResultUI (654 lines) - **CRITICAL:** Sets `Time.fixedDeltaTime = 0f` to freeze physics. If scene reloads or restart is triggered without restoring this, **physics is permanently broken**. - **Strengths:** Clean mode-specific stats display (Cash System vs Practice) #### PreMatchIntroUI (430 lines) - **Strengths:** Coroutine-driven, no per-frame cost when hidden - **Uses sprites from SelectionOptions (recently fixed)** #### MinimapManager (209 lines) - **CONCERN:** Calls `FindObjectOfType()` every ~1s via `FindPlayer()`. Should use `CashSystemManager.Instance` (singleton already exists). ### 3.4 CORE INFRASTRUCTURE #### GameEvents (155 lines) — CRITICAL ARCHITECTURE - **Strengths:** ~25 static `Action` events with `?.Invoke()` — zero allocation pub/sub - **CRITICAL:** **No event cleanup on scene unload.** Static events persist across scenes. If a subscriber is destroyed without unsubscribing, the delegate holds a reference to a destroyed object → `MissingReferenceException`. Needs a `ClearAll()` method called on scene transitions. #### ObjectPool (290 lines) - **Concern:** `PooledObject.Update()` runs every frame on every pooled object with `autoReturnDelay > 0` — adds up with many VFX pooled objects - **Concern:** `ReturnAll()` creates `new List(_inUse)` — allocation during return operation - **Concern:** `DontDestroyOnLoad` on pool containers means pools survive scene changes but references to scene objects become stale #### EntityRegistry (90 lines) - **Strengths:** Generic static registry replacing `FindObjectsOfType`, O(1) register, O(n) queries - **Concern:** `Register()` uses `List.Contains()` — O(n) dedup check on every register. Should use HashSet. - **Concern:** Lambda predicates in `FindNearest`/`FindWithinRadius` may allocate closures if not cached #### CharacterPrefabManager (206 lines) - **Concern:** Hardcoded path strings (`"Rabbit"`, `"Cheetah"`) — should be data-driven via ScriptableObject - **Note:** `aiPrefabPaths` dictionary may be redundant (comment says "AI NOW USES SAME UNIFIED PREFABS AS PLAYER") #### GameManager (402 lines) - **Concern:** Static `Instance` without clear `DontDestroyOnLoad` guard — possible double-instantiation - **Concern:** Commented-out code blocks throughout — dead code ### 3.5 PLAYER SYSTEM #### HealthNew (1259 lines) — **WORST GOD CLASS** - **CRITICAL:** `Update()` runs every frame on **EVERY character** (6 in 3v3): - Sets `healthSlider.value` even when health hasn't changed - Calls `Camera.WorldToScreenPoint()` for AI health bar positioning every frame - Checks particle VFX state based on health threshold per frame - **CRITICAL:** 1259 lines mixing health logic, damage processing, health bar UI, death screen, reward screen, stamina, VFX — massive SRP violation - **Concern:** `FindObjectOfType()` in death/game-over paths - **Concern:** 20+ `Debug.Log` calls - **Concern:** `Instantiate(healthBarPrefab)` per character in Start without pooling #### CharacterInputHandler (357 lines) - **Strengths:** Enabled/disabled on character switch (only 1 active at a time), cached components - **Concern:** Public fields (`block`, `dodge`, `attackEnabled`) without validation — external code can modify freely ### 3.6 COMBAT SYSTEM #### EnemyTargetDetector (212 lines) - **Strengths:** Zero-allocation design with pre-allocated collider buffer, `OverlapSphereNonAlloc`, FOV/LOS filtering — **excellent mobile practice** #### FaceTargetOnAttack (254 lines) - **Strengths:** `Update()` early-returns when `!assistActive` (near-zero idle cost), `HashSet` for O(1) animation lookup, proper event subscribe/unsubscribe lifecycle ### 3.7 SAVE SYSTEM #### SaveManager (176 lines) - **Concern:** `async void` on `SaveGame()` and `InitializeSaveSystem()` — unobserved exceptions risk silent failures - **Concern:** Each stat mutation (`AddWin`, `AddLoss`, `AddMatch`) triggers immediate save — no batching/debouncing - **Dead code:** Server sync entirely commented out #### JsonDataService (82 lines) - **CONCERN:** XOR cipher with hardcoded key `"YOUR_ENCRYPTION_KEY"` — zero security - **Concern:** Synchronous file I/O on main thread — small data but could hitch on slow storage #### GameData (51 lines) - **No schema versioning** — field changes break old saves silently - **Mixes UI state** (`completed_missions_toAnimate`, `animation_status`) into persistent data - **No currency/gem fields** — shop system unimplemented ### 3.8 ASSET LOADING #### RemoteAssetBundleManager (664 lines) - **Custom replacement for Unity Addressables** — JSON catalog from remote server, coroutine-based download - **Concern:** Addressables package (2.8.1) still in manifest.json despite being fully replaced — wasted dependency - **Strengths:** Configurable memory cleanup (`Resources.UnloadUnusedAssets + GC.Collect`), retry logic, stall detection ### 3.9 SPECIAL MOVE CARD SYSTEM #### CardSpawner — `CARD_SYSTEM_DISABLED = true` - **Entire subsystem is dead code** — the card system is globally disabled - **No pooling** — cards use `Instantiate`/`Destroy` per spawn cycle ### 3.10 PLAYER MANAGEMENT #### PlayerManagerNew (330 lines) - **Concern:** `GameObject.Find("GameStatsManager")` in Awake — string-based lookup wrapped in try-catch swallowing errors - **Concern:** `Update()` polls `retry` and `pause` bools every frame — should be event-driven - **Mixes responsibilities:** gameplay state + audio settings + UI management #### AnimationManager (319 lines) - **Concern:** Uses **reflection** (`typeof(AnimationNames).GetFields()`) to auto-populate animation mappings — unnecessary when a static dictionary would suffice - **Concern:** 50+ lines of manual animation name remapping — should be data-driven (SO/JSON) --- ## 4. CRITICAL PERFORMANCE ANTI-PATTERNS ### 🔴 SEVERITY: CRITICAL (fix immediately) | # | Anti-Pattern | Location | Impact | |---|---|---|---| | 1 | **Static fields in CharacterMovement** shared across ALL instances | `CharacterMovement.cs` | Game-breaking: changing gravity/jump for one character affects all 6 | | 2 | **Timer event fires every frame** | `CashSystemManager.Update()` → `GameEvents.FireTimerUpdated()` | All subscribers (CashSystemUI etc.) process every frame unnecessarily | | 3 | **HealthNew.Update() on all 6 characters** sets slider, repositions bars, checks VFX | `HealthNew.cs` | 6× per-frame: Camera.WorldToScreenPoint + slider.value + VFX check | | 4 | **Time.fixedDeltaTime = 0f never restored** | `MatchResultUI.Show()` | Physics permanently broken after match result if scene not fully reloaded | | 5 | **No GameEvents.ClearAll() on scene transitions** | `GameEvents.cs` | MissingReferenceException on scene reload — delegates hold dead references | ### 🟠 SEVERITY: HIGH (fix before release) | # | Anti-Pattern | Location | Impact | |---|---|---|---| | 6 | 26 GB DEVIS folder in project | `Assets/DEVIS/` | 92.8% of project size — should be excluded from version control and builds | | 7 | 80 recovery scene duplicates | `Assets/_Recovery/` | 348 MB of dead scene files | | 8 | 17 duplicate animator controllers in Resources | `Assets/Resources/` | All loaded into memory at build time (Resources folder = always included) | | 9 | 50+ `Debug.Log` calls with string interpolation | Multiple files | GC allocation per log call on mobile; string.Format boxing | | 10 | Addressables package still in manifest | `Packages/manifest.json` | Unused 2.8.1 dependency bloating build; conflicts with custom bundle system | | 11 | PostProcessing v2 alongside URP | `Packages/manifest.json` | Redundant — URP has built-in Volume post-processing | | 12 | Android Target SDK 30 | `ProjectSettings.asset` | Google Play requires API 34+ since Aug 2024 — **blocks store submission** | | 13 | Gamma color space | `ProjectSettings.asset` | Incorrect lighting/HDR with URP; Linear required for physically-correct rendering | | 14 | Engine code stripping disabled | `ProjectSettings.asset` | Significantly larger APK/AAB | | 15 | GPU Skinning disabled | `ProjectSettings.asset` | 6 skinned characters = CPU skinning bottleneck on mobile | ### 🟡 SEVERITY: MEDIUM (optimize for performance) | # | Anti-Pattern | Location | Impact | |---|---|---|---| | 16 | `FindObjectOfType()` every ~1s | `MinimapManager.FindPlayer()` | Should use existing singleton Instance | | 17 | `FindObjectOfType()` in death paths | `HealthNew.cs` | Runtime lookup on critical path | | 18 | `GameObject.Find("GameStatsManager")` in Awake | `PlayerManagerNew.cs` | String-based runtime lookup | | 19 | `PooledObject.Update()` per-frame timer on all pooled objects | `ObjectPool.cs` | Per-frame cost scales with pool size | | 20 | CashBag.Update() idle animation on 15 bags | `CashBag.cs` | 15 Update calls for visual-only bobbing | | 21 | `EntityRegistry.Register()` uses List.Contains() | `EntityRegistry.cs` | O(n) dedup on every register call | | 22 | Reflection for animation mapping | `AnimationManager.cs` | `typeof().GetFields()` in Awake — unnecessary | | 23 | `GetComponent()` per attack event | `PlayerController.cs` | Uncached component lookup on input event | | 24 | 3 redundant AI controller classes | Multiple files | Maintenance burden: CharacterAIController, EnemyAIController, TeamAIController | | 25 | SaveManager writes per stat mutation (no batching) | `SaveManager.cs` | Multiple rapid file writes after match end | | 26 | `async void` on save methods | `SaveManager.cs` | Unobserved exception risk | --- ## 5. MISSING FEATURES / GAPS | Feature | Status | Notes | |---------|--------|-------| | **Shop/Currency System** | ❌ Not implemented | Unity IAP (4.14.2) in manifest but no ShopManager code | | **Online Multiplayer** | ❌ Not implemented | No Netcode/Photon/Mirror packages found | | **Analytics Integration** | ⚠️ Package only | `com.unity.analytics` present but no custom event tracking in code | | **Localization** | ❌ Not implemented | All strings hardcoded in English | | **Accessibility** | ❌ Not implemented | No colorblind mode, no text scaling, no screen reader support | | **Data Versioning** | ❌ Missing | `GameData` has no schema version field — save migration impossible | | **Crash Reporting** | ❌ Not implemented | `mono_crash.mem.*.blob` files present in root — crashes happening but not tracked | | **Performance Profiling Hooks** | ❌ Not implemented | No custom profiler markers, no frame budget tracking | | **Memory Budget System** | ❌ Not implemented | No texture quality tiers, no LOD on models | | **Loading Screen Tips** | ⚠️ Hardcoded | Hint strings in `AssetBundleDownloadManager` are not data-driven | | **Tutorial/Onboarding** | ❌ Not found | No tutorial system scripts | --- ## 6. DEPENDENCY AUDIT ### Packages to REMOVE (unused/redundant): | Package | Reason | |---------|--------| | `com.unity.addressables` 2.8.1 | Fully replaced by custom `RemoteAssetBundleManager` | | `com.unity.addressables.android` 1.0.9 | Same — custom system replaces this | | `com.unity.postprocessing` 3.5.1 | Redundant with URP Volume-based post-processing | | `com.unity.visualscripting` 1.9.9 | No evidence of use in codebase | | `com.unity.ai.assistant` + `.generators` + `.inference` + `.toolkit` | Pre-release AI tools — editor bloat | ### Packages to UPDATE: | Package | Current | Required | Reason | |---------|---------|----------|--------| | `com.unity.cinemachine` | 2.10.5 | 3.x | CinemachineV2 is legacy; V3 has better mobile perf | --- ## 7. ASSET SIZE BREAKDOWN ``` Assets Total: 28.0 GB ├── DEVIS/ (art source): 26.0 GB ← 92.8% — MUST exclude from build ├── _Recovery/: 348 MB ← DELETE (80 duplicate scenes) ├── UI/: 234 MB ├── Future UI Sound Lib: 220 MB ← Audit: likely includes unused sounds ├── LowPoly Fantasy Bags: 131 MB ├── Scenes/: 89 MB ← 2 main scenes = 81 MB (40+41 MB each!) ├── Material/: 80 MB ├── New UI/: 60 MB ├── GooglePlayPlugins/: 43 MB ├── Hovl Studio/: 38 MB ├── Audio/: 23 MB ├── Hit & Slashes copy: 18 MB ├── Scripts/: 2.9 MB ├── Resources/: 1.7 MB └── Everything else: ~5 MB ``` ### Critical Asset Concerns: 1. **Scene files are 40+ MB each** — `Game.unity` and `CITY_DONE.unity` are bloated. Likely contain embedded lightmaps, navigation data, or un-stripped mesh data. 2. **371 materials for a 6-character fighting game** — many are likely unused asset store imports. 3. **328 FBX models** — far more than needed for 6 characters + 1 arena. Audit for unused models. 4. **Textures >1MB:** PBR diffuse/normal maps up to 24 MB — uncompressed PNGs that should use ASTC compression on mobile. 5. **"Future UI Sound Library" (220 MB)** and **"Hit & Slashes Vol.3 copy" (18 MB)** — asset store packs likely containing mostly unused audio. --- ## 8. SINGLETON REGISTRY | Singleton | Pattern | DontDestroyOnLoad | Notes | |-----------|---------|-------------------|-------| | `GameManager` | Manual static Instance | ⚠️ Unclear | May double-instantiate on scene reload | | `SelectionOptions` | Manual static Instance | ✅ Yes | Carries team data + sprites cross-scene | | `CharacterPrefabManager` | Manual static Instance | ✅ Yes | Name → prefab path map | | `CashSystemManager` | Manual static Instance | ❌ No | Per-scene lifetime | | `SaveManager` | Manual static Instance | ✅ Yes | File I/O | | `UIManager` | Generic `Singleton` base | ⚠️ Via base | Thin wrapper | | `RemoteAssetBundleManager` | Lazy auto-creation | ✅ Yes | Can create orphans during shutdown | | `PoolManager` | Manual static Instance | ✅ Yes | Pool registry | **No service locator or DI container.** All inter-system communication is via: 1. Singleton references (`CashSystemManager.Instance`, etc.) 2. Static event bus (`GameEvents`) 3. `FindObjectOfType` / `GameObject.Find` (legacy patterns still present) --- ## 9. EVENT FLOW DIAGRAM ``` MATCH START │ PreMatchIntroUI.Show() │ ┌──────────┴──────────┐ │ │ SpawnTeams() IntroSequence() │ │ │ 3-2-1-FIGHT! │ │ cashUI.ShowHUD() intro.IsComplete = true │ ▼ ┌─────────────────────────────────────────────┐ │ GAMEPLAY LOOP │ │ │ │ CashSystemManager.Update() │ │ ├── FireTimerUpdated(timer) ────────▶ CashSystemUI.OnTimerUpdated() │ ├── FireScoreChanged(team,score) ───▶ CashSystemUI.OnScoreChanged() │ ├── Check win threshold │ │ └── Check buzzer beater │ │ │ │ CashBagSpawner (wave coroutine) │ │ ├── Pool.Get() → CashBag │ │ └── EntityRegistry.Register(bag) │ │ │ │ CashBag ──OnTriggerEnter──▶ CashCarrier.AddBag() │ ├── FireBagPickedUp() ──────▶ CashSystemUI pickup flash │ └── FireBagPickedUp() ──────▶ MatchStatTracker.OnBagPickedUp() │ │ │ TeamVault.MagnetPulse → Deposit │ │ ├── FireCashDeposited() ────▶ CashSystemUI vault bars │ └── FireCashDeposited() ────▶ MatchStatTracker │ │ │ HealthNew.TakeDamage() │ │ ├── FireDamageDealt() ──────▶ MatchStatTracker │ └── Death → FireKill() ─────▶ CashSystemUI kill feed │ │ │ Character Switch (tap TeamHUDPanel) │ │ └── FireCharacterSwitched() ──▶ CashSystemUI, Minimap └──────────────────────┬──────────────────────┘ │ Timer expires / threshold hit │ FireMatchResult(playerWon) │ MatchResultUI.Show(playerWon) ├── Time.timeScale = 0 ├── PopulateStats() └── SaveManager.AddWin/Loss() ``` --- ## 10. PRIORITY RANKING FOR OPTIMIZATION ### Tier 1 — Ship-Blocking (must fix before any build) 1. **Static fields in CharacterMovement** — game-breaking shared state 2. **Android Target SDK 30** — Google Play store rejection 3. **Time.fixedDeltaTime = 0f** not restored — breaks physics 4. **GameEvents.ClearAll() missing** — MissingReferenceException on scene reload ### Tier 2 — Performance-Critical (major FPS/memory impact) 5. **HealthNew God Class refactor** — 6× per-frame Update is the biggest performance drain 6. **Timer event throttling** — reduce `FireTimerUpdated` from 60Hz to 4Hz 7. **26 GB DEVIS folder** — exclude from build/VCS 8. **Delete _Recovery folder** — 348 MB of dead scenes 9. **Strip Debug.Log calls** — 50+ string allocations per frame on mobile 10. **Enable engine code stripping** — reduce APK size significantly 11. **Enable GPU Skinning** — offload 6-character skinning to GPU 12. **Switch to Linear color space** — correct URP lighting ### Tier 3 — Architectural Debt (prevents feature development) 13. Consolidate 3 AI controllers into 1 unified system 14. Complete AIBrain migration (remove CashSystemAI) 15. Refactor HealthNew into Health + HealthBarUI + DeathHandler 16. Add save data versioning 17. Remove unused packages (Addressables, PPv2, Visual Scripting) 18. Replace `FindObjectOfType` / `GameObject.Find` with singleton/registry 19. Audit 371 materials, 328 models, 191 prefabs for unused assets 20. Fix canvas reference resolution (7680×4320 is extreme for mobile) --- *Report generated as part of the 6-step Mobile Optimization Engineering Audit.* *Next: STEP B — Mobile Optimization Research (best practices, citations, benchmarks)*