State
Purpose
State supplies reusable sampled values, versioned publication, observation and transition tables. Applications choose when to sample or transition; these types do not create threads or automatically synchronize an entire game.
Interface
Types below are in CE::State unless another namespace is shown.
Types and operations
API and purpose |
|---|
|
|
|
|
|
Choosing a state type
Need |
Purpose and details |
|---|---|
Compare successive samples |
Use |
Share the latest value |
Use |
React to setters |
Use |
Model behavior transitions |
Supply application-defined |
Usage
Choose a state type from the information a reader needs: successive local samples, the latest published value, immediate setter callbacks, or guarded behavior transitions. These are independent application-owned values rather than a runtime service that must be started.
---
config:
theme: base
themeVariables:
fontFamily: system-ui, sans-serif
fontSize: 14px
flowchart:
htmlLabels: true
curve: linear
nodeSpacing: 22
rankSpacing: 38
padding: 12
---
flowchart TB
accTitle: State · application state choices
accDescr: Local names omit State::; ambiguous nested namespaces remain qualified. Arrows point toward the API or type used, not call order or data flow. Methods beneath type names are selected application entry points; Implement hooks marks engine-invoked overrides. Dashed arrows mark optional choices.
k0(["Application<br/>state model"]):::app
k1["<b>StateTracker</b><br/><br/>update(T)<br/><br/>changed()<br/><br/>delta(): decltype(current() - previous())"]:::focal
k2["<b>StateMachine</b><br/><br/>add_transition(<br/>State,<br/>Trigger,<br/>State,<br/>StateMachine<State, Trigger>::Guard,<br/>StateMachine<State, Trigger>::Action)<br/><br/>trigger(Trigger)<br/><br/>state(): State"]:::focal
k3(["Application<br/>state producer"]):::app
k4["<b>VersionedVariable</b><br/><br/>set(T)<br/><br/>snapshot(): VersionedSnapshot<T><br/><br/>wait_for_change(since): VersionedSnapshot<T>"]:::focal
k5["<b>ObservedVariable</b><br/><br/>ObservedVariable(<br/>T,<br/>ObservedVariable<T, Observers>::Callback[])<br/><br/>set(T)<br/><br/>snapshot(): VersionedSnapshot<T>"]:::focal
k6["VersionedSnapshot"]:::focal
k7(["Application<br/>snapshot reader"]):::app
k8(["Application<br/>transition / observer hooks"]):::app
k0 --> k1
k0 --> k2
k3 --> k4
k3 --> k5
k4 --> k6
k7 --> k6
k5 --> k8
k2 --> k8
k7 --> k4
k7 -.-> k5
k5 --> k6
classDef focal fill:#e7f3ef,stroke:#387d6b,color:#153d33,stroke-width:1.2px
classDef neighbor fill:#f0f3f8,stroke:#8c9bb1,color:#35445b,stroke-width:1px
classDef app fill:#fff2df,stroke:#c09452,color:#674515,stroke-dasharray:5 3
classDef system fill:#eaf0fc,stroke:#617fab,color:#263f69,stroke-width:1.2px
linkStyle default stroke:#7e8fa7,stroke-width:1.2px
Local names omit State:: where unambiguous. Explore this diagram and its other views →
The engine dependency view also shows where existing services use shared construction.
Choose what a change means
Application question |
Choose |
Observation and execution |
|---|---|---|
What changed since my previous update? |
The caller supplies each sample; |
|
What is the latest value and its revision? |
|
|
What should run whenever a setter succeeds? |
Observers run on the setter’s thread, including equal sets, after the storage lock releases. |
|
Which guarded behavior transition is permitted? |
One caller triggers ordered rules; the first matching successful guard selects the transition. |
|
Must every occurrence reach consumers? |
Use event delivery rather than treating the latest value/revision as occurrence history. |
An observer that must mutate simulation-owned state should submit owned work to
Dispatch, rather than assume the setter runs on simulation.
wait_for_change() has no cancellation/timeout; keep the variable alive and
arrange for its producer and waiters to finish before destroying it. The
state guide
owns the detailed exception and callback rules.
Uses
Consumer |
Dependency supplied by the caller |
Requirement |
|---|---|---|
Sample type |
Defines copying, assignment, comparison and optional subtraction; the caller serializes access. |
|
Value type |
Copies value/revision under one storage lock. That lock does not extend pointee lifetimes or promise rollback for throwing assignment. |
|
|
Publishes before invoking observers; borrowed targets remain alive and protect themselves against overlapping callbacks. |
|
Application state/trigger types, guards and actions |
Owns the rule table and callable captures; no runtime, input or worker service is required. |
Used by
Consumer |
State helper |
Relationship |
|---|---|---|
Application models |
Sampled/publication/observer/transition types above |
The application chooses ownership, sampling and trigger boundaries; no global game state machine is prescribed. |
|
Publish deliberately shared service facades; explicit initialization must precede competing access when configuration matters. Assets. |
|
Offers the process-default event facade; independently owned buses remain possible. Events. |
||
Share acquisition facades while handles retain independent final-release contexts. Memory. |
Contracts
snapshot() copies a versioned value and revision together; separate getters may
observe different updates. Equal sets do not advance a versioned revision.
Waits coalesce updates and deliver current state rather than every intermediate
value. Assignment/copy exceptions retain the supplied type’s guarantee, not a
transactional rollback guarantee.
Observed callbacks run outside storage locks on the setter’s thread, including equal successful sets. Concurrent/reentrant setters can overlap callbacks. State-machine guards/rules have insertion order; failures stop transition steps without undoing prior callback effects. Do not recursively trigger the same machine.
Lifecycle
Own each value/machine within its application component. Keep borrowed callback targets alive through calls and capture destruction. Versioned waiters require a live variable and a producer able to make progress; destruction is not cancellation. Borrowed accessor references expire with their owner or mutation according to that type’s contract.
Execution
StateTracker and transition machines require caller synchronization.
Versioned storage synchronizes its value/revision, while callbacks protect their
own external targets. Select a Dispatch owner when an observer
must change simulation state from another producer.
Integration
Sample an application-owned score during update:
CE::State::StateTracker<int> score{0};
score.update(10);
if (score.changed()) {
const int gained = score.delta();
// Use gained while preparing the next HUD content update.
static_cast<void>(gained);
}
The tracker owns integer samples and introduces no clock. Keep it as a member to compare successive updates rather than reconstructing it every tick.
Limits and further reading
State publication is not event history, a completion barrier or automatic thread assignment. Read state and utility contracts, StateTracker, VersionedVariable, ObservedVariable and StateMachine.