Effect Pipeline And Modular Deployment¶
Purpose¶
This document defines the official architecture direction for gameplay effects, triggered sub-effects, modular deployment, and UX event emission.
It is written to support three goals at once:
- a clean gameplay rules pipeline
- extensibility for future expansions without monolithic deployment pressure
- reliable UX signaling when gameplay effects resolve
Current Foundation¶
The current codebase already has the correct architectural starting point:
- cards reference effect ids plus parameter bags
- effect behavior is implemented in C#
EffectRegistrydiscovers effect implementations from codeCardResolverexecutes card effects through the registryCombatHandlerPipelinealready supports event-driven mechanics
That foundation should be preserved, not replaced.
Official Rule: Effects Are Code Units¶
Each gameplay effect should exist as an explicit code unit that can be registered into the effect system.
The canonical model is:
- one effect id maps to one executable effect implementation
- effect parameters remain data-driven
- effects are composed into cards, relics, quests, enemies, realm passives, and scripted encounters through data
Content authors should be able to assemble behavior from registered effects, but the effect implementations themselves should remain code and tests.
Official Rule: Triggers Use A Sub-Pipeline¶
Triggered effects should not be handled as ad hoc special cases inside random effect classes.
They should run through a formal trigger sub-pipeline.
That trigger pipeline should:
- listen for structured gameplay events
- evaluate trigger conditions
- enqueue matching triggered effects
- resolve them in deterministic order
- emit UX events for what actually happened
Recommended Effect Layers¶
The recommended effect architecture is five layers.
1. Effect Definition Layer¶
This is the author-facing data record.
It should define:
effectIddisplayNameversioncategoryparameterSchemauxHintKeytagsmoduleId
2. Effect Execution Layer¶
This is the code implementation.
An effect implementation should:
- validate parameters
- inspect the execution context
- apply state changes
- publish structured gameplay events
- return a structured result payload
3. Trigger Layer¶
This is the sub-pipeline for triggered behavior.
A trigger definition should support:
eventTypeconditionscopefrequencyRuleprioritycooldownRulepayloadEffectIds
4. UX Event Layer¶
This is the bridge from rules to presentation.
Gameplay code should not call Unity animations or UI widgets directly.
Instead, the effect and trigger pipelines should emit structured UX events such as:
DamageAppliedBlockGainedStatusAppliedExecutionTriggeredConstructDestroyedRealmPassiveTriggeredRiftObjectiveUpdatedQuestBeatUnlocked
5. Module And Version Layer¶
This layer makes the system deployable without treating the whole game as one inseparable package.
Each effect should belong to a versioned module or capability pack.
Examples:
core.shared.combatcore.class.anchorcore.faction.aetharicampaign.rifts.protectionexpansion.glass_war
Recommended Runtime Flow¶
The recommended resolution flow is:
- content requests one or more effects by id
- the effect registry resolves the executable implementation
- the effect executes against a structured context
- the effect publishes gameplay-domain events
- the trigger sub-pipeline evaluates those events for follow-on effects
- triggered effects are enqueued and resolved deterministically
- the system emits UX event payloads derived from actual resolved outcomes
- telemetry records both primary and triggered resolution
Determinism Rule¶
Triggered effects must remain deterministic.
That means:
- trigger ordering rules must be explicit
- nested triggers must use stable queue semantics
- random outcomes inside effects must use seeded RNG scope keys
- identical starting state and seed must produce identical effect and trigger chains
Recommended Trigger Ordering¶
The suggested ordering model is:
- rule validation
- prevention and cancellation triggers
- primary effect resolution
- reactive triggers
- delayed triggers scheduled for later windows
- UX event emission after the resulting state is known
This avoids presentation lying about outcomes that were later modified or cancelled.
Suggested Interfaces¶
The exact code shape can evolve, but the official direction should look like this conceptually:
public interface IGameEffect
{
string EffectId { get; }
EffectManifest Manifest { get; }
ValueTask<EffectResult> ExecuteAsync(EffectExecutionContext context, JsonObject parameters, CancellationToken cancellationToken = default);
}
public interface IEffectTrigger
{
string TriggerId { get; }
TriggerManifest Manifest { get; }
bool Matches(GameplayEvent gameplayEvent, TriggerEvaluationContext context);
ValueTask<TriggeredEffectBatch> CreateEffectsAsync(GameplayEvent gameplayEvent, TriggerEvaluationContext context, CancellationToken cancellationToken = default);
}
public interface IGameplayUxEventMapper
{
IReadOnlyList<UxEvent> Map(EffectResult result, IReadOnlyList<GameplayEvent> gameplayEvents);
}
Non-Monolithic Deployment Direction¶
The user's stated goal is correct: the system should support dynamic expansion and deployment without forcing a full monolithic rules release every time content grows.
The recommended direction is capability-based modularity, not arbitrary hot-loading of untrusted gameplay code.
Recommended Deployment Model¶
- keep the shared execution contracts inside
EchoSpire.Core - load effect modules as signed, versioned assemblies that implement the known interfaces
- register module manifests at startup or controlled reload points
- store effect definitions and manifests in API-backed data
- allow content activation or deactivation by module, version, and environment
Why This Is Better Than Fully Dynamic Script Injection¶
- it preserves testability
- it preserves deterministic behavior
- it avoids security and sandboxing chaos
- it still allows expansion packs and feature modules to ship independently
Suggested Module Manifest Fields¶
Each effect module should declare:
moduleIdmoduleVersioncompatibleCoreVersionprovidedEffectsprovidedTriggersrequiredModulescontentNamespacesdeploymentRingsuch as dev, staging, livesignatureor trust metadata
Suggested Registry Behavior¶
The effect registry should evolve from simple assembly scanning into a manifest-aware registry.
Recommended capabilities are:
- register effect implementations from multiple modules
- reject duplicate effect ids unless version policy explicitly allows override
- expose effect metadata for Admin tooling
- expose compatibility failures clearly
- support dry-run validation before a module is activated
UX Event Emission Rule¶
The effect pipeline must be able to notify the UX layer without coupling gameplay code to a specific client.
The official pattern should be:
- gameplay code emits domain events and effect results
- a mapping layer converts them into client-facing UX events
- Unity, Console, and future clients interpret those UX events according to their own presentation capabilities
This preserves one rules engine with multiple presentation layers.
Recommended UX Event Payload Fields¶
Suggested UX event fields are:
eventTypesourceEntityIdtargetEntityIdseffectIdtriggerIdwhen applicablevaluestatusIdtimingWindowpresentationHintKeystackCountisCriticalMoment
Admin And Tooling Implications¶
If the system becomes modular, the admin tools should expose:
- effect catalog by module and version
- trigger catalog by event type
- parameter schema validation
- compatibility validation before publish
- preview of trigger chains and UX events
- environment-based activation toggles
Testing Requirements¶
Every effect module should ship with:
- unit tests for each effect
- trigger-chain tests for recursive or reactive behavior
- deterministic replay tests
- compatibility tests against the current core contracts
- UX mapping tests for presentation-critical outcomes
Current Official Recommendation¶
The recommended architecture is:
- keep effects as code, not opaque database logic
- keep effect composition data-driven
- formalize triggers as a sub-pipeline, not scattered conditional logic
- emit structured gameplay events and map them into UX events
- introduce manifest-aware, versioned effect modules for extensibility
- prefer controlled modular loading over free-form runtime scripting
What This Enables¶
If implemented well, this architecture enables:
- safer expansions
- cleaner balancing workflows
- independent effect-module deployment
- richer UI feedback
- better simulation analytics
- less pressure to treat the entire game as one monolithic release unit