Files
DeviantMobile-Rohan/STEP_A_PROJECT_ANALYSIS.md

34 KiB
Raw Blame History

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<T>     │    │ │
│  │  │ 25 static    │  │ Queue    │  │ Static per-type lists │    │ │
│  │  │ Action<T>    │  │ 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<CashSystemManager>() every ~1s via FindPlayer(). Should use CashSystemManager.Instance (singleton already exists).

3.4 CORE INFRASTRUCTURE

GameEvents (155 lines) — CRITICAL ARCHITECTURE

  • Strengths: ~25 static Action<T> 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<GameObject>(_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<PlayerManagerNew>() 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<string> 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<CashSystemManager>() every ~1s MinimapManager.FindPlayer() Should use existing singleton Instance
17 FindObjectOfType<PlayerManagerNew>() 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<InputToAnimation>() 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 eachGame.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<T> 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)

  1. HealthNew God Class refactor — 6× per-frame Update is the biggest performance drain
  2. Timer event throttling — reduce FireTimerUpdated from 60Hz to 4Hz
  3. 26 GB DEVIS folder — exclude from build/VCS
  4. Delete _Recovery folder — 348 MB of dead scenes
  5. Strip Debug.Log calls — 50+ string allocations per frame on mobile
  6. Enable engine code stripping — reduce APK size significantly
  7. Enable GPU Skinning — offload 6-character skinning to GPU
  8. Switch to Linear color space — correct URP lighting

Tier 3 — Architectural Debt (prevents feature development)

  1. Consolidate 3 AI controllers into 1 unified system
  2. Complete AIBrain migration (remove CashSystemAI)
  3. Refactor HealthNew into Health + HealthBarUI + DeathHandler
  4. Add save data versioning
  5. Remove unused packages (Addressables, PPv2, Visual Scripting)
  6. Replace FindObjectOfType / GameObject.Find with singleton/registry
  7. Audit 371 materials, 328 models, 191 prefabs for unused assets
  8. 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)