Skip to content

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#
  • EffectRegistry discovers effect implementations from code
  • CardResolver executes card effects through the registry
  • CombatHandlerPipeline already 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

The recommended effect architecture is five layers.

1. Effect Definition Layer

This is the author-facing data record.

It should define:

  • effectId
  • displayName
  • version
  • category
  • parameterSchema
  • uxHintKey
  • tags
  • moduleId

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:

  • eventType
  • condition
  • scope
  • frequencyRule
  • priority
  • cooldownRule
  • payloadEffectIds

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:

  • DamageApplied
  • BlockGained
  • StatusApplied
  • ExecutionTriggered
  • ConstructDestroyed
  • RealmPassiveTriggered
  • RiftObjectiveUpdated
  • QuestBeatUnlocked

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.combat
  • core.class.anchor
  • core.faction.aethari
  • campaign.rifts.protection
  • expansion.glass_war

The recommended resolution flow is:

  1. content requests one or more effects by id
  2. the effect registry resolves the executable implementation
  3. the effect executes against a structured context
  4. the effect publishes gameplay-domain events
  5. the trigger sub-pipeline evaluates those events for follow-on effects
  6. triggered effects are enqueued and resolved deterministically
  7. the system emits UX event payloads derived from actual resolved outcomes
  8. 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

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.

  • 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:

  • moduleId
  • moduleVersion
  • compatibleCoreVersion
  • providedEffects
  • providedTriggers
  • requiredModules
  • contentNamespaces
  • deploymentRing such as dev, staging, live
  • signature or 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.

Suggested UX event fields are:

  • eventType
  • sourceEntityId
  • targetEntityIds
  • effectId
  • triggerId when applicable
  • value
  • statusId
  • timingWindow
  • presentationHintKey
  • stackCount
  • isCriticalMoment

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