project-mobile-command/plans/DATA_DRIVEN_IMPLEMENTATION_PLAN.md
StillHammer 9b19242a99 Add data-driven architecture implementation plan
- Created DATA_DRIVEN_IMPLEMENTATION_PLAN.md with 8-phase roadmap
- Architecture: ProcessEngine for data-driven systems (MC + WF compatible)
- GameModule stays hardcoded, systems become JSON-configurable
- Estimated timeline: 23 days (4-5 weeks)
- Phases: ProcessEngine, Crafting, Combat, Events, Storage, Integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 07:14:10 +08:00

15 KiB

Mobile Command - Data-Driven Implementation Plan

Date: 2 décembre 2025 Architecture: Data-driven process engine (WarFactory-inspired) Status: Planning phase - Replacing hardcoded module logic


🎯 Vision

Créer un système data-driven où:

  • GameModule reste hardcodé (state machine C++, orchestration)
  • Systèmes de jeu sont data-driven (crafting, combat, events définis en JSON)
  • ProcessEngine interprète et exécute les process JSON
  • WarFactory compatibility - Architecture réutilisable entre projets

📐 Architecture Cible

GameModule.so (C++ hardcodé)
├─ State machine (MainMenu → TrainBuilder → Expedition → Combat)
├─ Appelle les systèmes via IIO pub/sub
└─ Coordonne le flow du jeu

ProcessEngine (lib statique partagée)
├─ Registry: "craft_recipe" → CraftProcessor
├─ Registry: "resolve_combat" → CombatProcessor
├─ Registry: "trigger_event" → EventProcessor
└─ execute(process_type, params_json, state)

CraftingSystemModule.so (data-driven)
├─ CraftingState (local)
├─ Utilise ProcessEngine
├─ Config: recipes.json
└─ IIO: "craft:start" → publish "craft:complete"

CombatSystemModule.so (data-driven)
├─ CombatState (local)
├─ Utilise ProcessEngine
├─ Config: combat_scenarios.json
└─ IIO: "combat:start" → publish "combat:ended"

EventSystemModule.so (data-driven)
├─ EventState (local)
├─ Utilise ProcessEngine
├─ Config: events.json
└─ IIO: "event:check" → publish "event:triggered"

🗂️ Structure du Projet

project-mobile-command/
├── src/
│   ├── main.cpp                          # GroveEngine mainloop
│   ├── process_engine/                   # Core data-driven engine
│   │   ├── ProcessEngine.h
│   │   ├── ProcessEngine.cpp
│   │   ├── IProcessor.h                  # Interface pour processors
│   │   └── processors/                   # Process implementations
│   │       ├── CraftProcessor.cpp
│   │       ├── CombatProcessor.cpp
│   │       └── EventProcessor.cpp
│   │
│   └── modules/
│       ├── GameModule.cpp                # Orchestrator (hardcodé)
│       │
│       ├── systems/                      # Data-driven systems
│       │   ├── CraftingSystemModule.cpp
│       │   ├── CombatSystemModule.cpp
│       │   ├── EventSystemModule.cpp
│       │   └── StorageSystemModule.cpp
│       │
│       └── mc_specific/                  # MC-only modules
│           ├── TrainBuilderModule.cpp
│           └── ExpeditionModule.cpp
│
├── config/
│   ├── game.json                         # GameModule config
│   ├── systems/                          # System definitions
│   │   ├── crafting_recipes.json
│   │   ├── combat_scenarios.json
│   │   ├── events.json
│   │   └── storage.json
│   │
│   └── mc_specific/                      # MC-specific configs
│       ├── train.json
│       └── expeditions.json
│
└── tests/
    ├── ProcessEngineTest.cpp
    ├── CraftingSystemTest.cpp
    └── IntegrationTest.cpp

📋 Phase 1: ProcessEngine Foundation

Objectif: Créer le moteur générique qui interprète les process JSON

Tasks

1.1 ProcessEngine Core

class ProcessEngine {
public:
    using ProcessFunc = std::function<void(
        const IDataNode& params,  // JSON config
        IDataNode& state,          // Module state
        IIO* io                    // Pub/sub
    )>;

    void registerProcess(const std::string& type, ProcessFunc func);
    void execute(const std::string& processType,
                 const IDataNode& params,
                 IDataNode& state,
                 IIO* io);
};

Fichiers:

  • src/process_engine/ProcessEngine.h
  • src/process_engine/ProcessEngine.cpp
  • src/process_engine/IProcessor.h (interface commune)

Tests:

  • tests/ProcessEngineTest.cpp
  • Test registry (register/execute)
  • Test unknown process type handling

1.2 CMake Integration

  • Créer lib statique ProcessEngine
  • Link dans chaque module data-driven
  • Headers publics exposés

Durée estimée: 1-2 jours


📋 Phase 2: Crafting System (Data-Driven)

Objectif: Premier système data-driven complet

2.1 CraftProcessor

Logic:

void CraftProcessor::execute(const IDataNode& params, IDataNode& state, IIO* io) {
    // 1. Parse params (recipe_id, inputs, outputs, duration)
    // 2. Check inventory in state
    // 3. Consume inputs
    // 4. Add craft job to queue
    // 5. Publish "craft:started"
}

Fichiers:

  • src/process_engine/processors/CraftProcessor.cpp
  • src/process_engine/processors/CraftProcessor.h

2.2 CraftingSystemModule

State:

{
  "inventory": {
    "scrap_metal": 100,
    "ammunition": 500
  },
  "craft_queue": [
    {"recipe": "repair_kit", "time_remaining": 25.3}
  ]
}

Config (config/systems/crafting_recipes.json):

{
  "recipes": {
    "repair_kit": {
      "process": "craft_recipe",
      "inputs": {"scrap_metal": 5, "electronics": 1},
      "outputs": {"repair_kit": 1},
      "duration": 30.0
    },
    "drone_recon": {
      "process": "craft_recipe",
      "inputs": {"drone_parts": 3, "electronics": 2},
      "outputs": {"drone_recon": 1},
      "duration": 120.0
    }
  }
}

Topics:

  • Subscribe: "craft:start" → {recipe_id}
  • Publish: "craft:started" → {recipe_id, duration}
  • Publish: "craft:complete" → {recipe_id, outputs}
  • Publish: "inventory:changed" → {resource_id, delta, total}

Fichiers:

  • src/modules/systems/CraftingSystemModule.cpp
  • src/modules/systems/CraftingSystemModule.h
  • config/systems/crafting_recipes.json

Tests:

  • tests/CraftingSystemTest.cpp
  • Test craft avec resources suffisantes
  • Test craft avec resources insuffisantes
  • Test craft queue progression
  • Test hot-reload state preservation

Durée estimée: 2-3 jours


📋 Phase 3: Combat System (Data-Driven)

Objectif: Système de combat avec formules configurables

3.1 CombatProcessor

Logic:

void CombatProcessor::execute(const IDataNode& params, IDataNode& state, IIO* io) {
    // 1. Parse scenario (enemy stats, formulas)
    // 2. Setup combatants
    // 3. Resolve rounds (hit calculation, damage, casualties)
    // 4. Determine outcome (victory/defeat)
    // 5. Publish "combat:ended" avec loot/casualties
}

Config (config/systems/combat_scenarios.json):

{
  "scenarios": {
    "scavenger_ambush": {
      "process": "resolve_combat",
      "enemy": {
        "firepower": 30,
        "armor": 10,
        "morale": 60,
        "count": 8
      },
      "formulas": {
        "hit_chance": "accuracy * (1.0 - cover)",
        "damage": "max(0, firepower - armor * 0.5)",
        "morale_loss": "casualties / total * 100"
      },
      "loot": {
        "scrap_metal": {"min": 10, "max": 30},
        "ammunition": {"min": 20, "max": 100}
      }
    }
  }
}

Formula Parser:

  • Simple expression evaluator (pour prototype)
  • Variables: accuracy, cover, firepower, armor, etc.
  • Opérations: +, -, *, /, max(), min()

Fichiers:

  • src/process_engine/processors/CombatProcessor.cpp
  • src/process_engine/FormulaEvaluator.h (helper)
  • src/modules/systems/CombatSystemModule.cpp
  • config/systems/combat_scenarios.json

Tests:

  • Test formulas parsing
  • Test combat resolution
  • Test loot distribution
  • Test casualties

Durée estimée: 3-4 jours


📋 Phase 4: Event System (Data-Driven)

Objectif: Système d'événements scriptés avec conditions et outcomes

4.1 EventProcessor

Logic:

void EventProcessor::execute(const IDataNode& params, IDataNode& state, IIO* io) {
    // 1. Evaluate conditions (game_time, location, resources)
    // 2. Trigger event si conditions met
    // 3. Handle player choice
    // 4. Apply outcomes (resources, flags, trigger_combat)
}

Config (config/systems/events.json):

{
  "events": {
    "scavenger_encounter": {
      "process": "trigger_event",
      "title": "Scavengers Spotted",
      "description": "Your scouts report a small group nearby.",
      "conditions": {
        "game_time_min": 600,
        "location_type": "urban_ruins"
      },
      "choices": [
        {
          "id": "attack",
          "text": "Attack immediately",
          "outcomes": {
            "trigger_combat": "scavenger_ambush",
            "morale": -5
          }
        },
        {
          "id": "negotiate",
          "text": "Attempt to trade",
          "requirements": {"reputation": 20},
          "outcomes": {
            "resources": {"ammunition": -50, "food": +30},
            "morale": +5
          }
        },
        {
          "id": "avoid",
          "text": "Move on quietly",
          "outcomes": {
            "time_cost": 60
          }
        }
      ]
    }
  }
}

Fichiers:

  • src/process_engine/processors/EventProcessor.cpp
  • src/modules/systems/EventSystemModule.cpp
  • config/systems/events.json (5 events minimum)

Tests:

  • Test conditions evaluation
  • Test event triggering
  • Test outcomes application
  • Test choice requirements

Durée estimée: 2-3 jours


📋 Phase 5: GameModule Integration

Objectif: GameModule orchestre tous les systèmes data-driven

5.1 GameModule Updates

State Machine (reste hardcodé):

enum class GameState {
    MainMenu, TrainBuilder, Expedition, Combat, Event, Pause
};

void GameModule::updateExpedition(float dt) {
    // Publish event checks
    auto checkEvent = make_unique<JsonDataNode>("check");
    checkEvent->setDouble("game_time", m_gameTime);
    checkEvent->setString("location", m_currentLocation);
    m_io->publish("event:check", move(checkEvent));

    // Handle incoming events
    if (m_io->hasMessages()) {
        auto msg = m_io->pullMessage();
        if (msg.topic == "event:triggered") {
            transitionToState(GameState::Event);
        }
    }
}

Topics Orchestration:

  • Subscribe à tous les *:complete / *:ended
  • Publish vers systèmes via craft:start, combat:start, etc.
  • Gère transitions d'état

Fichiers:

  • Update src/modules/GameModule.cpp
  • Subscribe tous les nouveaux topics
  • Wire systems ensemble

Durée estimée: 2 jours


📋 Phase 6: Storage System

Objectif: Save/load de tous les états data-driven

6.1 Storage Format

{
  "version": "0.1.0",
  "timestamp": "2025-12-02T10:30:00Z",
  "game_state": "Expedition",
  "game_time": 3600.5,
  "modules": {
    "GameModule": {...},
    "CraftingSystem": {...},
    "CombatSystem": {...},
    "EventSystem": {...}
  }
}

Fichiers:

  • src/modules/systems/StorageSystemModule.cpp
  • Collect states via IIO broadcast
  • Save to JSON
  • Restore states on load

Durée estimée: 2 jours


📋 Phase 7: MC-Specific Modules

Objectif: Modules spécifiques Mobile Command (pas data-driven)

7.1 TrainBuilderModule

Responsabilités:

  • Balance train (latéral/longitudinal)
  • Wagon management
  • Performance malus

Topics:

  • Publish: "train:composition_changed"
  • Publish: "train:performance_updated"

Config: config/mc_specific/train.json

7.2 ExpeditionModule

Responsabilités:

  • Lancer expéditions
  • Team composition (humains + drones)
  • Return avec loot

Topics:

  • Subscribe: "craft:complete" (drones)
  • Publish: "expedition:started", "expedition:returned"

Config: config/mc_specific/expeditions.json

Durée estimée: 3-4 jours


📋 Phase 8: Integration & Testing

Objectif: Loop complet fonctionnel

8.1 Integration Tests

  • Full loop test: craft → expedition → combat → event → return
  • Save/load cycle complet
  • Hot-reload tous modules
  • Pub/sub message flow validation

8.2 Main.cpp Updates

std::vector<std::pair<std::string, std::string>> moduleList = {
    // Game orchestrator
    {"GameModule", "game.json"},

    // Data-driven systems
    {"CraftingSystemModule", "systems/crafting_recipes.json"},
    {"CombatSystemModule", "systems/combat_scenarios.json"},
    {"EventSystemModule", "systems/events.json"},
    {"StorageSystemModule", "systems/storage.json"},

    // MC-specific
    {"TrainBuilderModule", "mc_specific/train.json"},
    {"ExpeditionModule", "mc_specific/expeditions.json"}
};

Durée estimée: 2-3 jours


📊 Timeline Estimé

Phase Durée Cumul Livrable
Phase 1: ProcessEngine 2 jours 2j Core engine fonctionnel
Phase 2: Crafting 3 jours 5j Premier système data-driven
Phase 3: Combat 4 jours 9j Combat data-driven
Phase 4: Events 3 jours 12j Events data-driven
Phase 5: GameModule 2 jours 14j Orchestration complète
Phase 6: Storage 2 jours 16j Save/load
Phase 7: MC Modules 4 jours 20j Train + Expeditions
Phase 8: Integration 3 jours 23j Loop complet

Total: ~23 jours de dev (4-5 semaines)


🎯 Critères de Succès

Technique

  • ProcessEngine avec 3+ processors (craft, combat, event)
  • 3+ systèmes data-driven fonctionnels
  • Hot-reload préserve état
  • Pub/sub communication fluide
  • Tests unitaires pass

Gameplay

  • Craft 5+ items
  • Combat 3+ scenarios différents
  • Trigger 5+ events
  • Save/load fonctionne
  • Loop complet 30+ minutes jouable

Réutilisabilité

  • ProcessEngine utilisable pour WarFactory
  • Pas de hardcode MC-specific dans systems/
  • JSON configs clairs et documentés

🔄 Comparaison Avant/Après

Avant (Architecture actuelle)

ResourceModule.cpp (478 lignes)
├─ Logic craft hardcodée
├─ Formulas en C++
└─ Config JSON minimal

→ Changer formule = recompiler
→ Pas réutilisable WF

Après (Architecture data-driven)

CraftingSystemModule.cpp (150 lignes)
├─ Utilise ProcessEngine
└─ Config recipes.json complet

CraftProcessor.cpp (100 lignes)
└─ Logic générique réutilisable

→ Changer formule = edit JSON
→ ProcessEngine réutilisable WF

🚀 Prochaines Étapes Immédiates

  1. Créer structure ProcessEngine (Phase 1)
  2. Implémenter CraftProcessor (Phase 2)
  3. Tester avec CraftingSystemModule (Phase 2)
  4. Valider hot-reload (Phase 2)

📝 Notes Importantes

Design Decisions

  1. GameModule reste hardcodé - State machine C++ pour clarté
  2. Systems sont data-driven - Réutilisabilité MC/WF
  3. ProcessEngine est stateless - State vit dans modules
  4. IIO pour tout - Découplage maximal

Risks

  • Formula parser complexity - Garder simple pour prototype
  • JSON configs verbeux - Trade-off accepté pour flexibilité
  • Hot-reload edge cases - Tester intensivement

Future Enhancements

  • Expression parser avancé (Lua?)
  • Visual process editor
  • Process debugging tools
  • Performance profiling

Plan créé le 2 décembre 2025 Architecture inspirée de WarFactory worldgen