Ownership & Registration
finders keepers, foxes weepers
Each component type is stored by exactly one Aspect per World. You declare who owns what with Owns – everything you don't declare belongs to Main.
Declaring Ownership
Owns is fluent and comes in a generic, a params Type[], and an all-in-one flavor:
var visuals = world.AddAspect("visuals")
.Owns<Position>()
.Owns<Velocity>();var visuals = world.AddAspect("visuals")
.Owns(typeof(Position), typeof(Velocity));var visuals = world.AddAspect("visuals", typeof(Position), typeof(Velocity));Re-registering a type to the same Aspect is a harmless no-op – Owns just smiles and returns the Aspect for further chaining.
Routing Rules
- A component type has one owning Aspect per World.
- Types nobody
Ownsare stored inMain(unless strict mode says otherwise). - Registering a type that another Aspect already owns throws an
InvalidOperationExceptionthat politely names the current owner. No custody battles.
world.AddAspect("visuals").Owns<Position>();
var game = world.AddAspect("game");
game.Owns<Position>(); // 💥 InvalidOperationException:
// Component type Position is already owned by Aspect "visuals"
// and cannot be re-registered to "game".Ownership Freezes at First Use
THE FREEZE RULE
The moment a component type materializes in any Archetype – usually because some Entity innocently Added it – its ownership is frozen for the lifetime of the World. Registering it afterwards throws:
using var world = new World();
var visuals = world.AddAspect("visuals");
world.Spawn().Add(new Position(1, 2)); // Position routes to Main... and freezes there
visuals.Owns<Position>(); // 💥 InvalidOperationException:
// Component type Position is already in use by Aspect "main" - ownership
// freezes at first use. Register it via Owns<T>() before the first Entity
// or Archetype uses the type.
THE ANTIDOTE
Register all your Aspects in your World subclass's constructor (as shown in the Quick Start). Nothing can materialize a type before the constructor finishes, so nothing can freeze you out.
StrictAspects
For those who like their storage layout load-bearing, StrictAspects turns implicit routing off entirely. Every component type must be registered to an Aspect before use – unregistered types throw instead of quietly moving in with Main.
using var world = new World { StrictAspects = true };
world.AddAspect("game").Owns<CrewData>();
var entity = world.Spawn(); // fine - the entity column is always exempt
entity.Add(new CrewData(5)); // fine - registered
entity.Add(new Position(1, 2)); // 💥 InvalidOperationException:
// World requires Aspect ownership for all Component types
// (StrictAspects = true), but Position is not owned by any Aspect.
SUPERNERD PRO TIP
Strict mode is a great safety net for larger projects: a typo'd or forgotten registration fails loudly at the first Add, instead of silently fragmenting Main and showing up months later in a profiler trace at 2am.
The Entity Exception
The entity column lives in every Aspect (it's how each Aspect tracks its members), so no single Aspect may own it – Owns<Entity>() throws:
InvalidOperationException: The entity column is present in every Aspect
and cannot be owned by one.It's also why plain Spawn() works even in strict mode: the entity column is always exempt from registration, and every spot that resolves a Query to its Aspect deliberately skips it, so it never drags a Query toward any particular Aspect.
Where to next?
Ownership settled? Learn how Entities actually join and leave Aspects.