[priority: high] gameStore.ts tick() orchestrates 7 stores with tangled cross-store coupling #103
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: High — the core game loop has tight coupling to 7 sibling stores, making it fragile and hard to modify.
Findings:
tick()callsgetState()on 7 different stores: useUIStore, usePrestigeStore, useManaStore, useCombatStore, useCraftingStore, useAttunementStore, useDisciplineStorecraftingStore.tscreatestempState = { ...get(), rawMana } as any— wide parameter bagsAffected files:
src/lib/game/stores/gameStore.tssrc/lib/game/stores/craftingStore.tssrc/lib/game/stores/combat-actions.tssrc/lib/game/stores/manaStore.ts,src/lib/game/stores/prestigeStore.tsSuggested fix: Refactor to a pipeline pattern: read all states → compute all updates → write all states. Each store should compute its own next state from inputs. Add rehydration checks using Zustand's
_hasRehydratedflag.Confidence: High
Dimension: mid_level_elegance (score: 60.0%) / initialization_coupling
Starting work on refactoring gameStore.ts tick() to use a pipeline pattern. Current analysis complete — the tick() function has 7 getState() calls, ad-hoc partial state objects, and back-and-forth writes across store boundaries. Plan: create a TickPipeline that reads all states → computes all updates → writes all states, with rehydration guards.
Analysis Summary
Current problems in
tick():getState()calls at the top (ui, prestige, mana, combat, crafting, attunement, discipline)getState()calls for cross-store writes (useUIStore, usePrestigeStore, useManaStore, useCombatStore, useAttunementStore)craftingStore.tscreatestempState = { ...get(), rawMana } as any— wide parameter bag anti-patterncombat-actions.tscallsusePrestigeStore.getState().signedPactsinside the combat loopProposed fix — TickPipeline pattern:
TickContext— a single read-only snapshot of all store states at tick startTickResult— a single write-batch with all state updatescomputeTick(ctx: TickContext): PartialStatemethodtick()orchestrates: read all → compute all → write all_hasRehydratedflaggetState()calls from combat-actions.ts and craftingStore.tsFiles to modify:
src/lib/game/stores/gameStore.ts— main refactoringsrc/lib/game/stores/combat-actions.ts— pass signedPacts as parametersrc/lib/game/stores/craftingStore.ts— remove tempState anti-patternsrc/lib/game/stores/tick-pipeline.ts— pipeline types and orchestrationEstimated scope: Medium — refactoring only, no new features.
Resolution Summary
Refactored
gameStore.ts tick()from a tangled cross-store orchestrator to a clean read → compute → write pipeline.Changes
New file:
src/lib/game/stores/tick-pipeline.ts—TickContext,TickWritestypes +buildTickContext()/applyTickWrites()orchestratorModified files:
gameStore.ts—tick()now: (1) snapshots all 7 store states into aTickContext, (2) computes all updates into aTickWritesbatch, (3) applies all writes viaapplyTickWrites(). Eliminated all mid-functiongetState()calls.combat-actions.ts—processCombatTick()now acceptssignedPacts: number[]as an explicit parameter instead of callingusePrestigeStore.getState().signedPactsinside the combat loop. ReturnsCombatTickResultwith full combat state for the write batch.combatStore.ts/combat-state.types.ts— UpdatedprocessCombatTicksignature to pass throughsignedPacts.craftingStore.ts— RemovedtempState = { ...get(), rawMana } as anyanti-pattern.startPreparingnow passesrawManaas an explicit parameter.preparation-actions.ts— Refactored to acceptrawMana: numberdirectly instead of reading from aGameStatebag.Verification