Gameplay State Ownership
Almost every "where should this live?" question in UE5 has one correct answer, and it is
determined by a single property: how long the state must survive.
The classes exist at different lifetimes. State placed in a class that dies sooner than the
state needs is lost; state placed in a class that outlives it leaks into the next round and
appears as a bug that only shows up on the second playthrough. Both are decided at the moment
the variable is declared, and both are cheap then and expensive later — moving state is not a
refactor of one field, it is a refactor of everything that reads it.
The default failure is putting things on the Pawn, because the Pawn is what you have a
pointer to. A Pawn is one of the shortest-lived things in the project.
Assign by lifetime, before declaring the variable
- Ask how long the state must live, in these terms: shorter than one possession, one
possession, the whole match, across level transitions, or across sessions. That answer
selects the owner almost by itself. See
references/lifetime-table.md.
- Ask who needs to read it. State that many unrelated systems read from a deep object
graph is a sign the owner is too low in the hierarchy.
- Never place state on a Pawn that must survive the Pawn. Destruction, respawn, and
possession changes all end a Pawn's life while the game continues.
- Distinguish "match rules" from "match state". The rules object and the shared state
object are different, and putting observable state in the rules object is a common error
with a delayed cost.
- Prefer a subsystem over a singleton or static. Subsystems have defined lifetimes and
deterministic teardown; a static has neither, and gives you state that survives things it
should not. See
references/subsystems.md.
- Record the assignment in the project context file, with the lifetime that justified
it. The lifetime is the reason; without it the table is unmaintainable.
Load only what applies:
references/lifetime-table.md — the lifetime-to-owner
mapping, with the questions that disambiguate the hard cases.
references/misplacement-costs.md — what each wrong
placement costs, and the symptom that reveals it.
references/subsystems.md — the subsystem scopes, when each
is right, and why they beat singletons.
Required answer format
When this skill fires, return:
- State table — state | required lifetime | owner class | who reads it.
- Justification — for each entry, the lifetime event that rules out the next-shorter
owner.
- Reset behavior — what happens to each entry at respawn, round end, and level
transition, stated explicitly rather than inherited.
- Access paths — how each reader reaches the state, and any that traverse more than two
hops.
- Subsystem choices — for any subsystem, which scope and why.
- Not verified — anything whose required lifetime is genuinely unknown, marked rather
than guessed.
Hard rules
- Never store state on a Pawn that must survive destruction, respawn, or a possession change.
- Never store persistent player-associated state on a Controller if it must survive a level
transition; check what your project's transitions actually preserve rather than assuming.
- Match rules and match state are separate concerns. Anything that must be observed by
other systems belongs in the shared state object, not the rules object.
- No statics or ad-hoc singletons for gameplay state. Use a subsystem with the narrowest
scope that covers the required lifetime.
- Every piece of state has a defined reset behavior at every boundary it survives. Undefined
reset behavior is the mechanism behind "only wrong on the second round".
- Choose the narrowest scope that satisfies the lifetime. Wider scopes are not safer; they
are a different bug — state that persists past its meaning.
Verification
The destruction test. Destroy and respawn the Pawn mid-session. Every value that should
persist must persist; every value that should reset must reset. This single test catches the
most common misplacement in UE5 projects, and it takes one console command.
The second-round test. Play two rounds without restarting the process. State that leaks
between rounds appears here and nowhere else — a first round is always clean, which is why
this class of bug reaches release.
The transition test. Cross a level transition and audit the table. Which owners survive a
transition is project-configuration dependent; verify it rather than reasoning about it.
Reachability audit. For each entry, count the hops from a typical reader to the state.
Long chains are a design signal: the state is owned too low, and every reader is paying for
it.
Scope
This skill decides where state lives. It does not cover serialization and save games, which
add a persistence question on top of a lifetime question, nor the content or design of the
state itself.
It does not cover network replication or authority. Those questions layer onto this one, and
getting ownership right first makes them tractable — but nothing here is sufficient for a
networked project, and replication may be banned in your phase anyway
(ue5-phase-bans).
1---2name: ue5-gameplay-state-ownership3description: Decide which UE5 class owns each piece of runtime gameplay state by matching it to the lifetime the state must survive — Pawn, Controller, PlayerState, GameState, GameMode, or an engine subsystem — so that state does not vanish when a Pawn is destroyed, persist when it should reset, or become unreachable from the systems that need it. Use when adding any persistent value, when state is lost on respawn or level transition, when a singleton or static is proposed, or when deciding where score, progression, settings, or match state should live.4---56# Gameplay State Ownership78Almost every "where should this live?" question in UE5 has one correct answer, and it is9determined by a single property: **how long the state must survive.**1011The classes exist at different lifetimes. State placed in a class that dies sooner than the12state needs is lost; state placed in a class that outlives it leaks into the next round and13appears as a bug that only shows up on the second playthrough. Both are decided at the moment14the variable is declared, and both are cheap then and expensive later — moving state is not a15refactor of one field, it is a refactor of everything that reads it.1617The default failure is putting things on the Pawn, because the Pawn is what you have a18pointer to. A Pawn is one of the shortest-lived things in the project.1920## Assign by lifetime, before declaring the variable21221. **Ask how long the state must live**, in these terms: shorter than one possession, one23 possession, the whole match, across level transitions, or across sessions. That answer24 selects the owner almost by itself. See25 [`references/lifetime-table.md`](references/lifetime-table.md).262. **Ask who needs to read it.** State that many unrelated systems read from a deep object27 graph is a sign the owner is too low in the hierarchy.283. **Never place state on a Pawn that must survive the Pawn.** Destruction, respawn, and29 possession changes all end a Pawn's life while the game continues.304. **Distinguish "match rules" from "match state".** The rules object and the shared state31 object are different, and putting observable state in the rules object is a common error32 with a delayed cost.335. **Prefer a subsystem over a singleton or static.** Subsystems have defined lifetimes and34 deterministic teardown; a static has neither, and gives you state that survives things it35 should not. See [`references/subsystems.md`](references/subsystems.md).366. **Record the assignment** in the project context file, with the lifetime that justified37 it. The lifetime is the reason; without it the table is unmaintainable.3839Load only what applies:4041- [`references/lifetime-table.md`](references/lifetime-table.md) — the lifetime-to-owner42 mapping, with the questions that disambiguate the hard cases.43- [`references/misplacement-costs.md`](references/misplacement-costs.md) — what each wrong44 placement costs, and the symptom that reveals it.45- [`references/subsystems.md`](references/subsystems.md) — the subsystem scopes, when each46 is right, and why they beat singletons.4748## Required answer format4950When this skill fires, return:51521. **State table** — state | required lifetime | owner class | who reads it.532. **Justification** — for each entry, the lifetime event that rules out the next-shorter54 owner.553. **Reset behavior** — what happens to each entry at respawn, round end, and level56 transition, stated explicitly rather than inherited.574. **Access paths** — how each reader reaches the state, and any that traverse more than two58 hops.595. **Subsystem choices** — for any subsystem, which scope and why.606. **Not verified** — anything whose required lifetime is genuinely unknown, marked rather61 than guessed.6263## Hard rules6465- Never store state on a Pawn that must survive destruction, respawn, or a possession change.66- Never store persistent player-associated state on a Controller if it must survive a level67 transition; check what your project's transitions actually preserve rather than assuming.68- Match rules and match state are separate concerns. Anything that must be *observed* by69 other systems belongs in the shared state object, not the rules object.70- No statics or ad-hoc singletons for gameplay state. Use a subsystem with the narrowest71 scope that covers the required lifetime.72- Every piece of state has a defined reset behavior at every boundary it survives. Undefined73 reset behavior is the mechanism behind "only wrong on the second round".74- Choose the narrowest scope that satisfies the lifetime. Wider scopes are not safer; they75 are a different bug — state that persists past its meaning.7677## Verification7879**The destruction test.** Destroy and respawn the Pawn mid-session. Every value that should80persist must persist; every value that should reset must reset. This single test catches the81most common misplacement in UE5 projects, and it takes one console command.8283**The second-round test.** Play two rounds without restarting the process. State that leaks84between rounds appears here and nowhere else — a first round is always clean, which is why85this class of bug reaches release.8687**The transition test.** Cross a level transition and audit the table. Which owners survive a88transition is project-configuration dependent; verify it rather than reasoning about it.8990**Reachability audit.** For each entry, count the hops from a typical reader to the state.91Long chains are a design signal: the state is owned too low, and every reader is paying for92it.9394## Scope9596This skill decides *where state lives*. It does not cover serialization and save games, which97add a persistence question on top of a lifetime question, nor the content or design of the98state itself.99100It does not cover network replication or authority. Those questions layer onto this one, and101getting ownership right first makes them tractable — but nothing here is sufficient for a102networked project, and replication may be banned in your phase anyway103(`ue5-phase-bans`).