Skip to content

[Architecture] Add server-authoritative extensible gameplay state for players, entities, and world objects #63

@yunnwi

Description

@yunnwi

Summary

Add a generic engine/SDK primitive for server-authoritative gameplay state that can be attached to players, entities, world positions, chunks/regions, or mod-defined objects.

This should be a reusable foundation for Vanilla, mods, custom experiences, and standalone games.

Vanilla hotbar / selected block / inventory should be built on top of this primitive, not as private Vanilla-only HashMap state. Mods and non-Vanilla games should be able to use the same system for their own authoritative gameplay state.

This is not an inventory-specific proposal. Inventory, hotbar, selected block, equipment, gas masks, machines, skills, factions, and custom-game loadouts are all examples of gameplay state that should share the same underlying authority/persistence/replication primitive.

Problem / Motivation

Freven already has a good server-authoritative action/mutation foundation:

  • clients submit actions as intent
  • server action handlers receive player_id and context
  • server validates actions
  • server applies authoritative block mutations through BlockAuthority
  • clients may provide predicted edits, but the server result is authoritative

This is enough for simple hardcoded interactions.

However, larger gameplay systems need persistent/extensible server-owned state associated with players, entities, world objects, or mod-defined simulation objects.

Examples:

  • Vanilla selected hotbar slot
  • Vanilla inventory / equipment
  • selected block for placement
  • custom tool mode
  • RPG skills
  • team/faction
  • gas mask/filter state
  • machine inventories
  • block/entity capabilities
  • per-player mod state
  • custom-game weapon loadouts
  • standalone games that do not use Vanilla at all

Without a generic gameplay state primitive, each gameplay layer has to invent private state storage. For example, Vanilla could implement selected_block as a HashMap<player_id, selected_block>, but that would not be a good long-term platform foundation:

  • mods could not reuse it cleanly
  • other game modes would need their own incompatible systems
  • persistence and replication rules would be ad hoc
  • reconnect/death/world reload behavior would be unclear
  • action handlers would not have a standard way to read/write authoritative gameplay state
  • client prediction/replication would become inconsistent across systems

Freven should provide the generic state/authority/replication foundation, while Vanilla and mods define the actual gameplay meaning.

Current state

Current SDK/engine contracts already provide part of the foundation:

  • ClientActionRequest carries action kind, opaque payload, input sequence anchor, and predicted edits
  • ActionContext provides player_id, character physics, block world, block authority, services, and block_id_by_key
  • BlockAuthority::try_apply provides authoritative mutation outcomes
  • Vanilla place already validates target, reach, solidity, and applies SetBlock server-side

This is good and should remain generic.

What appears to be missing is a public generic gameplay state model that is:

  • server-authoritative
  • scoped to player/entity/world/chunk/position/object
  • optionally persistent
  • optionally replicated
  • accessible from action handlers and guest/runtime systems
  • owned/namespaced by mods or gameplay layers
  • versioned/migratable

Proposed direction

Introduce a generic server-authoritative gameplay state system.

The system should allow mods, Vanilla, and custom games to attach named state to well-defined owners/scopes.

Possible owner scopes:

  • player_id
  • entity_id
  • world id
  • chunk/region id
  • block/world position
  • mod-defined object id

Possible state identity:

  • owner scope
  • owner id
  • mod id / namespace
  • state key

Example conceptual keys:

  • freven.vanilla:hotbar attached to player
  • freven.vanilla:selected_slot attached to player
  • yunnwi.gas:mask_filter attached to player
  • yunnwi.ecology:tree_state attached to structure/object
  • custom.game:weapon_loadout attached to player
  • mod.machine:inventory attached to block position/object

The engine/platform should own:

  • authority boundary
  • save/load lifecycle
  • replication policy
  • dirty tracking
  • versioning/migration hooks
  • diagnostics
  • access control / namespace isolation

Mods/gameplay layers should own:

  • schema/serialization for their state
  • gameplay semantics
  • validation rules
  • when/how state changes

Action handlers and runtime guests should be able to access this state through SDK services.

Example long-term Vanilla place flow:

  1. Client presses key 1.
  2. Client submits select_slot action.
  3. Server validates and writes freven.vanilla:selected_slot for that player.
  4. Client right-clicks.
  5. Client submits place_selected action.
  6. Server reads selected_slot and hotbar from authoritative player state.
  7. Server validates placement permissions/reach/target.
  8. Server applies BlockAuthority mutation.
  9. Engine sends authoritative result/corrections/replicated state updates.

The client should not be trusted to say “place block id X” unless the server can validate that this block is actually available in the player's authoritative state.

Alternatives considered

  1. Vanilla-private HashMap state

Vanilla could store selected block / selected slot in an internal HashMap keyed by player_id.

This is enough for an MVP, but not a good platform foundation. Mods and standalone games would not get reusable state, persistence, replication, or interoperability.

  1. Put selected block directly in every action payload

This keeps the action stateless, but makes the client too authoritative unless the server has another state source to validate against.

It also does not solve inventory, equipment, skills, tools, or other gameplay state.

  1. Let each mod invent its own storage

This is flexible but leads to incompatible systems, inconsistent save/load behavior, inconsistent replication, and poor debugging.

  1. Hardcode inventory/hotbar into engine

This would be too gameplay-specific. The engine should provide generic authoritative state primitives, not Vanilla-specific mechanics.

Ownership / boundary impact

Engine/platform:

  • owns authoritative state storage lifecycle
  • owns replication policy and synchronization
  • owns persistence hooks and dirty tracking
  • owns diagnostics and limits
  • does not know gameplay meanings such as hotbar, tree, gas, inventory, skill, or faction

SDK:

  • exposes state attach/query/update APIs
  • exposes typed or schema-backed helpers where appropriate
  • exposes state access to action handlers and guest runtime systems
  • documents scopes, authority, persistence, and replication policies

Vanilla:

  • implements selected slot, hotbar, inventory, equipment, and block placement on top of generic gameplay state
  • should not require special engine-only state paths

Mods:

  • attach their own player/entity/world/object state
  • can extend Vanilla systems where supported
  • can build non-Vanilla gameplay systems using the same primitives

Custom games / standalone products:

  • can build their own gameplay state model without depending on Vanilla

Non-goals

  • Hardcoding Vanilla inventory, hotbar, selected block, tools, or items into engine core
  • Designing the full Vanilla item/inventory system in this issue
  • Replacing the existing action pipeline
  • Making clients authoritative over gameplay state
  • Implementing a full UI/inventory screen immediately
  • Requiring every state value to be replicated to every client
  • Making this system inventory-specific; inventory should be one consumer built on top of the generic primitive

Open questions

  • What owner scopes should be supported in the first version?
  • Should state be schema-declared, opaque bytes, or both?
  • Should state APIs be synchronous services, event-based, or both?
  • How should state replication be configured?
    • server-only
    • owning client only
    • observers/watchers
    • public
  • How should persistence be configured?
    • transient session state
    • world save state
    • player profile state
    • instance/server state
  • How should state migration work across mod versions?
  • How should mods attach state to players/entities they do not own?
  • What access controls are needed between mods?
  • Should there be common standard capabilities such as inventory slots later, or should those live entirely in Vanilla/optional crates?

Expected follow-up work

If accepted, likely follow-up issues:

  • Define gameplay state owner scopes and identity model
  • Add server-side gameplay state store with namespace isolation
  • Add SDK service APIs for action handlers and guests
  • Add persistence policy and save/load lifecycle
  • Add replication policy for owner/observer/public state
  • Add diagnostics for state size, invalid schema, migration failure, and replication limits
  • Refactor Vanilla selected slot / block placement to use the generic state system
  • Later: define optional inventory/equipment interfaces on top of the state primitive
  • Later: support client prediction helpers for selected slot / equipment changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:triageNew / untriaged. Needs initial review and classification.type:architectureLong-term structural / contract / system design work, not just isolated implementation.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions