Gameplay · guide
Gameplay modules
What a game composes — stats, tags, definition types and systems — declared explicitly, with nothing scanned.
Edit this page on GitHubDocuments
What it is
An IGameplayModule is a unit of gameplay a game chooses to have: items, or combat, or its own guild
ranks. It declares its stats, the tags its own code needs, its definition types and its systems, and
a GameplayConfig composes the ones a game used into a GameplayComposition.
The engine's modules and a game's own are the same kind of object — doc 16's NetworkModule
discipline one level up: build the built-ins out of the primitive users get, so that the extension
point is the one the engine itself uses and therefore the one that works.
What it is for
Making "which gameplay does this game have" a question with a written answer. A realm builds its system list from the composition, a content build bakes its tags, and a diagnostic prints the whole thing — so "why does this game have an auction house" is not a search of the reference graph.
It is also what makes declining a library visible. Doc 28 ships twenty-odd packages precisely so an extraction shooter does not carry a threat table; a composition that silently pulled in a dependency would undo that, so a missing dependency is named and refused rather than satisfied.
Using it
Use<TModule>() has a new() constraint, so the compiler emits the constructor call at the call
site. Nothing is activated by name and nothing has to survive trimming — an assembly scan reads
metadata a trimmed publish has already deleted, and produces a game that works in development and
ships with no quests.
Build is where the composition is checked. Two modules declaring the same stat, two modules
claiming one definition type, and a module whose dependency nobody used are each a composition that
compiles, runs, and is wrong in a way nothing else reports.
⚠ A definition type needs [DataContract], because that alias is the !Tag a .vxdef names it
by. Declaring one without a descriptor is refused here, which is the only place that knows the type
was meant to be authorable at all. Two types sharing an alias is refused earlier and harder, by
TypeRegistry itself, from a module initializer.
⚠ Declare a tag your C# asks about. Most tags reach the table because a definition mentions
them; a tag only code knows — State.InCombat — is absent without builder.Tag(…), and every rule
mentioning it then resolves to an empty range and quietly matches nothing.
Examples
A module:
using Vixen.Core.Threading;using Vixen.Ecs.Systems;using Vixen.Gameplay;public sealed class CombatModule : IGameplayModule { public string Name => "Combat"; public void Configure(GameplayModuleBuilder builder) => builder .DependsOn<GameplayKernelModule>() .Attribute("Power", 100f) .Attribute("Health", 1000f, minimum: 0f) .Attribute("CritChance", 0.05f, minimum: 0f, maximum: 1f) .Tag("State.InCombat") .System(SystemPhase.Update, static () => new ThreatSystem());}public sealed class ThreatSystem : SystemBase { public override JobHandle Update(in SystemContext context, JobHandle dependency) => dependency;}Composing a game, and using what came out:
using Vixen.Gameplay;public sealed class InventoryModule : IGameplayModule { public int BagSlots { get; set; } = 4; public string Name => "Inventory"; public void Configure(GameplayModuleBuilder builder) => builder.Tag("Item.Soulbound");}static class Composition { public static GameplayComposition ForThisGame() => new GameplayConfig() .Use<GameplayKernelModule>() .Use<InventoryModule>(module => module.BagSlots = 5) .Build(); // The stats every module declared, compiled into one layout, is what a subject is made over. public static GameplaySubject NewCharacter(GameplayComposition composition) => new(composition.Attributes); // And the tags a module's own code needs go into the catalog beside the ones content mentions. public static DefinitionCatalog Bake(GameplayComposition composition) { var builder = new DefinitionCatalogBuilder(); foreach (var tag in composition.Tags) { builder.AddTag(tag); } return builder.Build(); }}See also
- Definitions — what a module's definition types become in a
.vxdef. - Attributes — what
Attribute(…)builds up. - Gameplay tags — where
Tag(…)ends up.