Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tier 3 WASM Mod Showcases

Extended examples demonstrating Tier 3 WASM mod capabilities. These showcase how the engine’s trait-abstracted subsystems (D041) enable total replacement of rendering, pathfinding, and AI — while the simulation, networking, and rules remain unchanged.

For the WASM host API, capabilities system, execution limits, and determinism constraints that make these showcases possible, see the parent page: Tier 3: WASM Modules.

3D Rendering Mods (Tier 3 Showcase)

The most powerful example of Tier 3 modding: replacing the entire visual presentation with 3D rendering. A “3D Red Alert” mod swaps sprites for GLTF meshes and the isometric camera for a free-rotating 3D camera — while the simulation, networking, pathfinding, and rules are completely unchanged.

This works because Bevy already ships a full 3D pipeline. The mod doesn’t build a 3D engine — it uses Bevy’s existing 3D renderer through the WASM mod API.

A 3D render mod implements:

#![allow(unused)]
fn main() {
// WASM mod: replaces the default sprite renderer
impl Renderable for MeshRenderer {
    fn render(&self, entity: EntityId, state: &RenderState, ctx: &mut RenderContext) {
        let model = self.models.get(entity.unit_type);
        let animation = match state.activity {
            Activity::Idle => &model.idle,
            Activity::Moving => &model.walk,
            Activity::Attacking => &model.attack,
        };
        ctx.draw_mesh(model.mesh, state.world_pos, state.facing, animation);
    }
}

impl ScreenToWorld for FreeCam3D {
    fn screen_to_world(&self, screen_pos: Vec2, terrain: &TerrainData) -> WorldPos {
        // 3D raycast against terrain mesh → world position
        let ray = self.camera.screen_to_ray(screen_pos);
        terrain.raycast(ray).to_world_pos()
    }
}
}

Assets are mapped in YAML (mod overrides unit render definitions):

# 3d_mod/render_overrides.yaml
rifle_infantry:
  render:
    type: mesh
    model: models/infantry/rifle.glb
    animations:
      idle: Idle
      move: Run
      attack: Shoot
      death: Death

medium_tank:
  render:
    type: mesh
    model: models/vehicles/medium_tank.glb
    turret: models/vehicles/medium_tank_turret.glb
    animations:
      idle: Idle
      move: Drive

Cross-view multiplayer is a natural consequence. Since the mod only changes rendering, a player using the 3D mod can play against a player using classic isometric sprites. The sim produces identical state; each client just draws it differently. Replays are viewable in either mode.

See 02-ARCHITECTURE.md § “3D Rendering as a Mod” for the full architectural rationale.

Custom Pathfinding Mods (Tier 3 Showcase)

The second major Tier 3 showcase: replacing how units navigate the battlefield. Just as 3D render mods replace the visual presentation, pathfinder mods replace the movement algorithm — while combat, building, harvesting, and everything else remain unchanged.

Why this matters: The original C&C Generals uses a layered grid pathfinder with surface bitmasks and bridge layers — fundamentally different from Red Alert’s approach. A Generals-clone mod needs Generals-style pathfinding. A naval mod needs flow routing. A tower defense mod needs waypoint constraint pathfinding. No single algorithm fits every RTS — the Pathfinder trait (D013) lets modders bring their own.

A pathfinder mod implements:

#![allow(unused)]
fn main() {
// WASM mod: Generals-style layered grid pathfinder
// (See research/pathfinding-ic-default-design.md § "C&C Generals / Zero Hour")
struct LayeredGridPathfinder {
    grid: Vec<CellLayer>,          // 10-unit cells with bridge layers
    zones: ZoneMap,                // flood-fill reachability zones
    surface_bitmask: SurfaceMask,  // ground | water | cliff | air | rubble
}

impl Pathfinder for LayeredGridPathfinder {
    fn request_path(&mut self, origin: WorldPos, dest: WorldPos, locomotor: LocomotorType) -> PathId {
        // 1. Check zone connectivity (instant reject if unreachable)
        // 2. Surface bitmask check for locomotor compatibility
        // 3. A* over layered grid (bridges are separate layers)
        // 4. Path smoothing pass
        // ...
    }
    fn get_path(&self, id: PathId) -> Option<&[WorldPos]> { /* ... */ }
    fn is_passable(&self, pos: WorldPos, locomotor: LocomotorType) -> bool {
        let cell = self.grid.cell_at(pos);
        cell.surface_bitmask.allows(locomotor)
    }
    fn invalidate_area(&mut self, center: WorldPos, radius: SimCoord) {
        // Rebuild affected zones, recalculate bridge connectivity
    }
}
}

Mod manifest and config:

# generals_pathfinder/mod.toml
[mod]
title = "Generals Pathfinder"
type = "pathfinder"
pathfinder_id = "layered-grid-generals"
display_name = "Generals (Layered Grid)"
version = "1.0.0"

[capabilities]
pathfinding = true

[config]
zone_block_size = 10
bridge_clearance = 10.0
surface_types = ["ground", "water", "cliff", "air", "rubble"]

How other mods use it:

# desert_strike_mod/mod.toml — a total conversion using the Generals pathfinder
[mod]
title = "Desert Strike"
pathfinder = "layered-grid-generals"

[dependencies]
"community/generals-pathfinder" = "^1.0"

Multiplayer sync: All players must use the same pathfinder — the WASM binary hash/version/config profile is validated in the lobby, same as any sim-affecting mod. If a player is missing the pathfinder mod, the engine auto-downloads it from the Workshop (CS:GO-style, per D030).

Performance contract: Pathfinder mods use a dedicated pathfinder_fuel_per_tick budget (separate from general WASM fuel). The engine monitors per-tick pathfinding time and deferred-request rates. The engine never falls back silently to a different pathfinder — determinism means all clients must agree on every path. If a WASM pathfinder exhausts its pathfinding fuel for the tick, remaining requests return PathResult::Deferred and are re-queued deterministically for subsequent ticks. Community pathfinders targeting ranked certification are expected to pass PathfinderConformanceTest and ic mod perf-test --conformance pathfinder on the baseline hardware tier (D045 policy).

Ranked policy: Community pathfinders are available by default in single-player/skirmish/custom lobbies, but ranked/community competitive queues reject them unless the exact hash/version/config profile has been certified and explicitly whitelisted.

Phase: WASM pathfinder mods in Phase 6a. The three built-in pathfinder presets (D045) ship as native Rust in Phase 2.

Custom AI Mods (Tier 3 Showcase)

The third major Tier 3 showcase: replacing how AI opponents think. Just as render mods replace visual presentation and pathfinder mods replace navigation algorithms, AI mods replace the decision-making engine — while the simulation rules, damage pipeline, and everything else remain unchanged.

Why this matters: The built-in PersonalityDrivenAi uses behavior trees tuned by YAML personality parameters. This works well for most players. But the RTS AI community spans decades of research — GOAP planners, Monte Carlo tree search, influence map systems, neural networks, evolutionary strategies (see research/rts-ai-extensibility-survey.md). The AiStrategy trait (D041) lets modders bring any algorithm to Iron Curtain, and the two-axis difficulty system (D043) lets any AI scale from Sandbox to Nightmare.

A custom AI mod implements:

#![allow(unused)]
fn main() {
// WASM mod: GOAP (Goal-Oriented Action Planning) AI
struct GoapPlannerAi {
    goals: Vec<Goal>,         // Expand, Attack, Defend, Tech, Harass
    plan: Option<ActionPlan>, // Current multi-step plan
    world_model: WorldModel,  // Internal state tracking
}

impl AiStrategy for GoapPlannerAi {
    fn decide(&mut self, player: PlayerId, view: &FogFilteredView, tick: u64) -> Vec<PlayerOrder> {
        // 1. Update world model from visible state
        self.world_model.update(view);
        // 2. Re-evaluate goal priorities
        self.goals.sort_by_key(|g| -g.priority(&self.world_model));
        // 3. If plan invalidated or expired, re-plan
        if self.plan.is_none() || tick % self.replan_interval == 0 {
            self.plan = self.planner.search(
                &self.world_model, &self.goals[0], self.search_depth
            );
        }
        // 4. Execute next action in plan
        self.plan.as_mut().map(|p| p.next_orders()).unwrap_or_default()
    }

    fn on_enemy_spotted(&mut self, unit: EntityId, unit_type: &str) {
        // Scouting intel → update world model → may trigger re-plan
        self.world_model.add_sighting(unit, unit_type);
        if self.world_model.threat_level() > self.defend_threshold {
            self.plan = None; // force re-plan next tick
        }
    }

    fn on_under_attack(&mut self, _unit: EntityId, _attacker: EntityId) {
        self.goals.iter_mut().find(|g| g.name == "Defend")
            .map(|g| g.urgency += 30); // boost defense priority
    }

    fn get_parameters(&self) -> Vec<ParameterSpec> {
        vec![
            ParameterSpec { name: "search_depth".into(), min: 1, max: 10, default: 5, .. },
            ParameterSpec { name: "replan_interval".into(), min: 10, max: 120, default: 30, .. },
            ParameterSpec { name: "defend_threshold".into(), min: 0, max: 100, default: 40, .. },
        ]
    }

    fn uses_engine_difficulty_scaling(&self) -> bool { false }
    // This AI handles difficulty via search_depth and replan_interval
}
}

Mod manifest:

# goap_ai/mod.toml
[mod]
title = "GOAP Planner AI"
type = "ai_strategy"
ai_strategy_id = "goap-planner"
display_name = "GOAP Planner"
description = "Goal-oriented action planning — multi-step strategic reasoning"
version = "2.1.0"
wasm_module = "goap_planner.wasm"

[capabilities]
read_visible_state = true
issue_orders = true
ai_strategy = true

[config]
search_depth = 5
replan_interval = 30

How other mods use it:

# zero_hour_mod/mod.toml — a total conversion using the GOAP AI
[mod]
title = "Zero Hour Remake"
default_ai = "goap-planner"

[dependencies]
"community/goap-planner-ai" = "^2.0"

AI tournament community: Workshop can host AI tournament leaderboards — automated matches between community AI submissions, ranked by Elo/TrueSkill. This is directly inspired by BWAPI’s SSCAIT tournament (15+ years of StarCraft AI competition) and AoE2’s AI ladder (20+ years of community AI development). The ic mod test framework (above) provides headless match execution; the Workshop provides distribution and ranking.

Phase: WASM AI mods in Phase 6a. Built-in PersonalityDrivenAi + behavior presets (D043) ship as native Rust in Phase 4.