ObjectDefinitionRegistry
The one table of what every moving object type is, how it is drawn and which shared rules apply to it.
Location
| Header | src/GalaxyEggbert/Game/ObjectDefinitionRegistry.hpp, src/GalaxyEggbert/Game/ObjectIcons.hpp |
|---|---|
| Sources | src/GalaxyEggbert/Game/ObjectDefinitionRegistry.cpp (the table), src/GalaxyEggbert/Game/ObjectIcons.cpp (animation frames) |
| Namespace | GalaxyEggbert::Game |
| Engine dependency | None. Both headers include only GalaxyEggbert/Def/ObjectType.hpp and the standard library. |
Purpose
A world's moving objects (lifts, enemies, treasure, eggs, keys, exits, effects, the enemy Blupis...) are
identified by a Def::ObjectType number from 0 to 203, the same numbers as the original game's
world files. ObjectDefinitionRegistry holds one ObjectDefinition per type: how it
renders, which texture sheet its sprite comes from, whether a world may place it, what kind of thing it is,
and a set of declarative capability flags such as "touching it kills" or "dynamite destroys it".
It is one of the project's two single sources of truth (the other is
BlockDefinitionRegistry for blocks). Rendering, the world loader,
InteractionSystem and the editor read
their per-type facts from here instead of keeping their own lists of type numbers.
GetObjIcon in ObjectIcons.cpp supplies the animation frame (sprite icon) for a
type at a given animation phase.
Collaborators
Uses
Def::ObjectType(include/GalaxyEggbert/Def/ObjectType.hpp): the type numbers, which must never be renumbered.ResolveObjectIconFrame(ObjectIcons.cpp): the frame tables taken from the original's animation data.
Used by
- WorldRuntime: skips records whose type is unsupported or
Null, readsmobileWorldSupportedandpatrolMotionwhile importing objects. - InteractionSystem: lifts, enemy contact, pickups, dynamite, exits and the compass target all test capability flags.
src/GalaxyEggbertCNA/GalaxyEggbertGameScene.cpp: callsResolveObjectVisualfor every object when it builds the frame for WorldRenderer.- The editor:
EditorPalette.cpp,ObjectPlacement.hpp(one exit per world, vialevelExit),ObjectPathMarkers.hpp(route cubes from the patrol fields),WorldEditorUpdate.cpp.
ObjectDefinition fields
Every field of struct ObjectDefinition, with the types the table in
ObjectDefinitionRegistry.cpp sets (as of 2026-11-10). Types not listed keep the default.
| Field | Values | Set for |
|---|---|---|
type | Def::ObjectType | Its own id, 0-203. |
renderMode | Hidden, Billboard (default), SolidCube | SolidCube: lifts 1, 47, 48 and the crate 12. Hidden: type 0 and unsupported types. |
textureSource | None, Element (default), ObjectM, Explo, Blupi, Blupi1, PhaseDependent | ObjectM: 1, 12, 47, 48 and 14, 15, 31, 35, 52. Explo: explosions and effects 8-11, 53, 90-93, 98-100. Blupi: 200. Blupi1: 32, 33, 201-203. PhaseDependent: the electric arc 38. |
placementKind | Null, Direct, Transient, Reserved (default) | Direct: placed directly in a world (40 types; the editor palette selects only these). Transient: created only at run time (explosions, splashes, projectiles...). Reserved: unidentified types. |
semanticKind | Null, Lift, Enemy, Collectible, Pickup, StaticObstacle, Projectile, Effect, MovingLevelObject, Avatar, Reserved | For example Lift 1, 47, 48; Collectible 5, 6, 7, 21, 49, 50, 51; StaticObstacle 12 (crate); Avatar 200-203. |
verticalPlacement | CellCenter | Every type today; ResolveObjectVisualCenterY is the one place a new policy would go. |
liftConveyorDirection | None, PositiveX, NegativeX | 47 carries towards +X, 48 towards -X. |
mobileWorldSupported | bool | Types found in the original's 78 world files; the text-world importer skips the rest. |
patrolMotion | bool | 2, 3, 4, 20, 32, 33, 44, 54. |
dynamiteDestructible | bool | 30 types (enemies, the crate, several pickups, the Blupi avatars). |
genericContactHazard | bool | 2, 3, 4, 16, 17, 20, 96, 97. |
genericContactHazardFeedback | Small (default), Big | Big for 17 and 20. |
genericContactHazardCrouchImmune | bool | 3. |
balloonPoppableHazard | bool | 3, 16, 96, 97. |
standardPickupTouch | bool | 5, 6, 7, 21, 25, 26, 29, 30, 31, 40, 49, 50, 51, 55. |
smallEnemy | bool | 4, 32, 33. |
lethalDecorContactHazard | bool | 201, 202, 203. |
levelExit | bool | 7 (exit) and 21 (secret exit). |
patrolTicksPerCell, patrolRestTicks | std::uint16_t, 20 Hz ticks | The original's per-type creature timing (BD-0016): 4: 30/20, 16: 10/0, 17: 15/47, 20: 8/8, 32: 8/25, 33: 10/23, 44: 6/4, 54: 20/200. 0 means no fixed timing (lifts vary per record). |
Key members
A selection of the public API of ObjectDefinitionRegistry.hpp and ObjectIcons.hpp
(types in signatures shortened: ObjectType is GalaxyEggbert::Def::ObjectType).
| Member | Signature | What it does |
|---|---|---|
MaxObjectType, DefinitionCount | static constexpr std::uint16_t MaxObjectType = 203; | The highest type id; the table has 204 entries. |
Instance | static const ObjectDefinitionRegistry& Instance() noexcept | The single, immutable table, built on first use. |
Get | const ObjectDefinition& Get(ObjectType type) const noexcept | The definition; an id above 203 gets a hidden "unsupported" definition. |
IsSupported | bool IsSupported(ObjectType type) const noexcept | True for ids 0-203. |
Resolve | ResolvedObjectVisual Resolve(ObjectType type, int phase, std::uint16_t visualIconOverride = 0) const noexcept | Render mode, texture sheet, icon and visibility for one object at one animation phase. |
GetObjectDefinition | inline const ObjectDefinition& GetObjectDefinition(ObjectType type) noexcept | The usual accessor: Instance().Get(type). |
IsSupportedObjectType | inline bool IsSupportedObjectType(ObjectType type) noexcept | Free-function form of IsSupported. |
ResolveObjectVisual | inline ResolvedObjectVisual ResolveObjectVisual(ObjectType type, int phase, std::uint16_t visualIconOverride = 0) noexcept | Free-function form of Resolve; what renderers call. |
ResolveObjectVisualCenterY | inline float ResolveObjectVisualCenterY(ObjectType type, float objectCenterY) noexcept | Vertical draw position from verticalPlacement (today always the cell centre). |
GetObjIcon | int GetObjIcon(ObjectType type, int phase) | Sprite icon for a type at an animation phase; returns ResolveObjectVisual(type, phase).icon. |
GetBulldozerIcon, GetFishIcon, GetBirdIcon, GetWaspIcon, GetBlupihIcon, GetBlupitIcon | int GetBulldozerIcon(bool patrolGoesLeftFromStart, int patrolStep, int patrolTimeTicks) (same shape for each) | Direction- and turn-aware icons for patrolling enemies, following the original's four-step patrol (dwell, advance, dwell, recede). |
GetCreatureIcon | int GetCreatureIcon(int patrolStep, int patrolTimeTicks) | The large creature (54), which has no left/right frames. |
GetElementIconUv, GetExploIconUv, GetBlupiIconUv | ObjectIconUv GetElementIconUv(int icon) | UV rectangle of an icon in element.png, explo.png or blupi.png/blupi1.png. |
ResolvedObjectVisual carries definition, renderMode, textureSource,
icon and visible. Resolve takes the icon from the frame tables, unless a
per-object visualIconOverride (a tile look, for example a lift's) is given: then the icon is that tile
and the sheet is object-m.png. For the phase-dependent arc (38) the sheet is blupi1.png
for the first 30 ticks of its 90-tick cycle and element.png after. An object is visible when its render
mode is not Hidden and its icon is not negative. Older predicates such as IsUniformCubeObject
and IsExploPngSourced remain as registry-backed compatibility accessors; new code uses
ResolveObjectVisual.
How it is used
Gameplay code asks a capability question instead of comparing type numbers. The dynamite blast in
src/GalaxyEggbert/Game/InteractionSystem.cpp:
for (auto& victim : objects)
{
if (!victim.active || &victim == &obj)
{
continue;
}
if (!GetObjectDefinition(victim.type).dynamiteDestructible)
{
continue;
}
...
The scene builder in src/GalaxyEggbertCNA/GalaxyEggbertGameScene.cpp resolves each object's look once
per frame and draws lifts and crates as textured cubes:
const auto visual = ResolveObjectVisual(obj.type, static_cast<int>(obj.phase), obj.visualIcon);
if (!obj.active || !visual.visible || visual.renderMode != ObjectRenderMode::SolidCube)
{
continue;
}
...
const auto tileUv = tileAtlas_.GetTileUv(visual.icon);
Whether a billboard icon is replaced by a 3D model pose is decided separately, by ObjectModelTable from
avatars3d/objects/<name>/icons.txt; the registry only names the icon.
Rules and invariants
- Single source of truth. A new object behaviour or a changed classification goes into this table first; consumers follow. Do not add parallel lists of type numbers elsewhere.
- The capability flags are deliberately not a general behaviour-dispatch table. Each one replaces an exact membership test whose members are treated identically at the call site; distinct state machines (a bulldozer, a fish) stay in code.
- Type ids are the original's and are stored in world files: never renumber them.
- The registry is engine-independent and immutable after construction.
- The patrol timing table is mirrored by
CREATURE_TIMINGintools/worldkit.py; change both together, then runtools/audit/patrol_envelope.py.
Tests
| ctest entry | Source | Checks |
|---|---|---|
VerifyDefinitionRegistries | tools/VerifyDefinitionRegistries.cpp | Every type 0-203 keeps its id, is supported, and has the expected texture sheet and capability flags; 204 is unsupported; Resolve(type, 0).icon equals GetObjIcon(type, 0); the arc's sheet switch at phase 30; the visual override. Also checks the block registry. |
VerifyGetObjIcon | tools/VerifyGetObjIcon.cpp | A regression lock on the frame arrays and divisors behind GetObjIcon. |
VerifyObjIconAgainstReferenceDoc | tools/VerifyObjIconAgainstReferenceDoc.cpp | Parses the animation tables in mobile-eggbert-reference/08-animations.md and compares GetObjIcon's frame counts with them (runs from the repository root). |
VerifyObjectModelTable | tools/VerifyObjectModelTable.cpp | The avatars3d/objects/ manifests and icons.txt files that map icons to model poses. |
VerifyInteractionSystem, VerifyShippedWorlds and VerifyGEEditorObjects exercise the
table indirectly through its consumers.
Related pages
- BlockDefinitionRegistry: the matching table for blocks
- MoveObjectRecord: how an object is stored in a world file
- WorldRuntime, InteractionSystem, WorldRenderer
- Tutorial: changing a block or object behaviour
- Object lifecycle
- Testing