public interface IDefaultComponent<TSelf> where TSelf : struct, IDefaultComponent<TSelf>Declares what a freshly created component of this type should hold, for the types whose zero is not a usable starting point.
Remarks
Opt-in, and a component that does not implement it costs nothing. Most components are data whose zero is a perfectly good starting point; this exists for the few whose zero is not merely unhelpful but reads as a defect — a black light, a camera with a zero far plane, a shot that is disabled as well as degenerate. Nothing is registered for a type that does not implement this, no storage path branches on it, and Add``1 is unchanged for everybody.
⚠ This is consulted where something creates a component from nothing, and nowhere else. The ECS hands back zeroed storage and continues to — a chunk row is a memset and Add``1 still writes default. What reads this is the authoring half: the editor's Add Component, and anything else building a value it is about to hand to a person to edit. That boundary is the whole reason this is an interface and not a field initializer: a field initializer runs on new T() and not on default(T), so it would be honoured on some paths and silently ignored on others, with nothing in the source saying which. AddDefault``1 is how the runtime asks for the same value on purpose.
⚠ Not a deserialization fallback. A saved component carries every field, so a load overwrites whatever it started from; a scene that omits a field means the field was authored as zero. Reading this on a load would make an old file change meaning.
Implementing it changes nothing about the type's layout, its size or what a saved scene holds — the member is static, so the struct is the same bytes it was.
The engine's own components implement it explicitly, which is the convention worth copying: it keeps the value where it already was — Lights.Default(kind), Camera.Perspective, TerrainComponent.Of(name) — instead of growing a second public name for it, so there is one place a default is written down and this is only the wiring that says which one a fresh component takes.
Fields and properties (1)
TSelf DefaultValueWhat a freshly created one holds.
Used by (18)
- AudioSourceVixen.Audio
- BuoyancyBodyVixen.Water.Physics
- CameraVixen.Engine
- CameraDirectorVixen.Engine
- CharacterMovementVixen.Physics
- LightVixen.Rendering
- MeshRenderableVixen.Rendering
- PostProcessVolumeVixen.Rendering
- SceneComponentRegistryVixen.Engine
- ShieldedVixen.Ecs.Tests
- TerrainComponentVixen.Rendering.Terrain
- ThrusterVixen.Engine.Tests
- VfxEmitterVixen.Rendering
- VirtualCameraVixen.Engine
- WaterBodyComponentVixen.Rendering.Water
- WaterZoneComponentVixen.Rendering.Water
- WorldVixen.Ecs
- LateDefaultedVixen.Editor.App.Tests