server: Add typed entity components - #1328
Open
cqdetdev wants to merge 13 commits into
Open
Conversation
Entities gain an open set of typed components stored on their handle, accessed through ComponentKey created by RegisterComponent. Components may implement TickerComponent to run per-tick logic, MetaSyncer to contribute client-visible metadata and NBTSaver to persist with the entity; saved data of unregistered component types or with malformed values round-trips through the world save untouched. MarkMetaDirty resends metadata after in-place mutation, ticking components are cached per entity so components may attach and detach components during their own tick, and Tx.SpawnEntity spawns any registered Spawner type by name, opening entity creation to external packages. Component attach order is preserved and deterministic, including for components restored from NBT. EntityMetadata converts values to their protocol-encodable equivalents and rejects values the protocol cannot encode at the call site, rather than failing every metadata packet sent later.
Components implementing world.MetaSyncer now contribute to the metadata sent for their entity. Component metadata is applied after the built-in metadata, overwriting values and combining flag bits, so external packages can sync custom entity state to clients without forking. Flag bits are combined matching the existing entry's type, as some flag keys, such as the player flags, hold a byte instead of an int64.
RegisterType creates a world.EntityType from a declarative Spec: name, optional client-side network ID, bounding box and default components. Specs and extra spawn components are validated eagerly, so unregistered component types, duplicates and multiple behaviours fail at init or at the spawn call site instead of at first use. Ent and Player run ticking components each tick before their own logic; an entity closed by one of its ticking components is not ticked further. The main behaviour is now optional so entities may be composed purely of components, and a Behaviour returned among a Spec's components becomes the entity's main behaviour, bridging existing behaviours into spec-based types at runtime.
Entity age was encoded in 20-second units but decoded in ticks, so an entity's age collapsed by a factor of 400 on every save and load cycle. Encode in ticks, matching the decoder and vanilla.
cqdetdev
force-pushed
the
entity-overhaul/components
branch
from
July 14, 2026 03:01
a45d807 to
3e38174
Compare
Collaborator
|
can you like stop giving up on your PRs 🙏🏻 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an open, typed component system to entities. This is the first of
three planned PRs modernising the entity API and is fully additive:
no existing API changes, no behavioural changes for existing entities,
and byte-identical network output for all built-in entity types. The
existing Behaviour model is untouched and continues to work.
Problem
Entity state and logic currently live in a single opaque value
(
EntityData.Data any) holding one Behaviour. In practice this closesthe entity system to external packages:
metadata from a fixed set of type assertions on known behaviours.
and the EntityType.
EntityRegistryConfig's closures.
What this adds
Typed components on entities, accessed through keys created at
registration:
Components may implement optional capabilities:
behaviour. Ticker lists are cached per entity, so components may
attach/detach components (including themselves) during their tick.
setters (SetScoreTag, SetVariant, SetScale, SetColour and SetFlag).
Runs after built-in metadata; Attach/Detach
resend automatically.
in chunk NBT. Data saved under component names not registered in the
running process round-trips losslessly to the next save.
Declarative entity types replacing hand-written EntityType
boilerplate, validated eagerly at registration (unregistered component
types, duplicates and multiple behaviours panic at init, not at first
spawn):
A Behaviour among a Spec's components becomes the entity's main
behaviour, so spec-based types get full existing physics today.
Open spawning — any registered spec type can be spawned by name
from block, item or user code, without touching EntityRegistryConfig:
Dependency
This PR pins HashimTheArab/gophertunnel#89, which adds the typed protocol metadata keys used here. The dependency PR is based on the exact gophertunnel revision Dragonfly already used, so the replacement adds no unrelated fork changes.