Skip to main content

Runtime Architecture

Guide

How the GCS runtime is layered: manager, state machine, state view, controller, flow execution, events, and presentation

Runtime layers

LayerMain typesResponsibilityRule for your code
ManagerGameCardManager, GCSApiHolds the active databases, the active battle, the run master deck, and the public entry pointExternal code starts with GCSApi
State machineBattleStateMachineOwns battle phases, turn transitions, choice waits, reward waits, and enemy turnsNever force phase changes; call StartBattle, TryPlayCard, EndPlayerTurn
State viewIBattleState, BattleStateViewExposes turn, energy, units, piles, played/drawn history, and effective card costsRead through GCSApi.Battle or the GCSApi helpers
ControllerIBattleController, BattleStateViewMutates health, armor, energy, statuses, cards, delayed triggers, variables, and summoned enemiesMutate through GCSApi or FlowGraph nodes, not by editing lists and fields
Flow executionGameCardFlowExecutor, EffectActionContextRuns card, status, and enemy FlowGraphs with source, target, card, battle, controller, and databases in scopeGraphs read and write through context helpers and controller actions
EventsGCSEvents, IGCSEventChannel, GCSEventNamesNotifies UI, integrations, and custom systems when battle state changesSubscribe with GCSApi shortcuts or typed named events
PresentationUnitView, FloatingTextSystem, FX nodes, demo UIShows state changes through UI, animation, VFX, SFX, floating text, and camera feedbackPresentation observes runtime results; it never owns gameplay rules

Read state versus mutate state

GCS separates read-only state from writable control

SurfaceTypeWhat it can do
GCSApi.BattleIBattleStateRead current turn, energy, player, piles, alive enemies, played/drawn history, and effective card cost
GCSApi.ControllerIBattleControllerEverything IBattleState can read, plus mutations that go through runtime rules
GCSApi helpersStatic methodsSafe, named shortcuts for the same common reads and writes
warning

Directly editing UnitState.Statuses, CardPile.Cards, or UnitState.CurrentHp bypasses hooks, events, UI updates, and validation; use controller-backed methods instead

Battle state model

A live battle contains:

StateMeaning
TurnNumberStarts at 1 and increments after each enemy phase resolves
IsPlayerTurnTrue during player turn start, action, and end phases; false during the enemy phase
PlayerEnergyEnergy still available this turn
PlayerUnitThe player's unit state
AliveEnemyUnitsEnemies still alive; dead units are excluded
HandPile, DrawPile, DiscardPile, ExhaustPileRuntime card zones
PlayedThisTurnCards played during the current turn, in play order
DrawnThisTurnCards drawn during the current turn, in draw order

The draw pile is ordered so the last element is the next card drawn

The Battle tab of the Game Card Monitor shows this model live in Play Mode: active encounter, phase, turn, a player snapshot, and the enemy list

Game Card Monitor Battle tab showing the live battle snapshot, player state, and enemy list

Unit state model

UnitState is the live unit record used by the battle

Field or propertyMeaning
UnitIdRuntime id used by UI and events
SourceThe authored GameUnit asset behind the unit
CurrentHp, MaxHpCurrent and maximum health
CurrentArmorCurrent armor
CurrentEnergyEnergy value on the unit; for the player's battle pool, read GCSApi.PlayerEnergy
StatusesRuntime stack counts by GameStatus
StatusAppliersThe unit that applied each status, when known
ActiveHooksRuntime hooks contributed by statuses and cards
WasAttackedThisTurnWhether the unit has been attacked this turn
SkipNextTurnsPending skipped turns
IsDeadTrue when current HP is 0 or below
HpPercentInteger percentage of current HP over max HP

For external reads, prefer GCSApi.Hp, GCSApi.MaxHp, GCSApi.Armor, GCSApi.HpPercent, GCSApi.HasStatus, and GCSApi.StatusesOn

Flow execution context

When a FlowGraph runs, GCS builds an execution context that carries:

Context valueWhat it means
SourceThe unit responsible for the behavior
HostThe unit or owner currently hosting the behavior
TargetThe chosen or resolved target
BattleRead-only battle state
ControllerRule-aware mutation surface
CardThe active card instance, when the graph is card-related
Status databaseActive status lookup
Card databaseActive card lookup
Enemy unit databaseActive enemy lookup

Built-in nodes use this context automatically; custom nodes should also read inputs and mutate state through the context and controller rather than through unrelated global lookups

The Game Card Monitor Flow tab lists every reported graph run, newest first, with its owner, trigger, node count, and duration:

Game Card Monitor Flow tab listing FlowGraph executions during a live battle

Waits and async presentation

The battle state machine can pause progression while presentation or player choices are still resolving

MechanismUsed for
Choice waitChoice nodes pause execution until the player picks or skips
Animation gateAnimation and presentation can hold phase transitions until a gated action completes
Flow waitWait nodes delay a continuation by seconds or by animation id
Reward waitAfter a win, reward selection keeps the battle waiting until applied or skipped

This is why custom UI should react to events and state changes instead of assuming one API call completes every visible step immediately

Integration boundaries

NeedRecommended surface
Custom battle UIGCSApi read helpers plus typed event shortcuts
Card play controlsGCSApi.CurrentHand, GCSApi.CanPlayCard, GCSApi.TryPlayCard, GCSApi.RequiresTarget
Unit panelsGCSApi.Player(), GCSApi.AliveEnemies(), unit helpers, HP/status/intent events
Content browserGCSApi.Cards, Decks, PlayerUnits, EnemyUnits, Statuses, Encounters, and the Find* helpers
Runtime mutation from external systemsGCSApi mutation helpers or GCSApi.Controller
Custom event bridgeGCSApi.Subscribe, GCSApi.Events, GCSApi.RaiseGameEvent, or GES bridge events

Avoid depending on demo-only components such as sample hand views, reward views, or scene-specific presenters unless you are modifying the demo itself