project-mobile-command/src/modules/core/StorageModule.h
StillHammer 0953451fea Implement 7 modules: 4 core (game-agnostic) + 3 MC-specific
Core Modules (game-agnostic, reusable for WarFactory):
- ResourceModule: Inventory, crafting system (465 lines)
- StorageModule: Save/load with pub/sub state collection (424 lines)
- CombatModule: Combat resolver, damage/armor/morale (580 lines)
- EventModule: JSON event scripting with choices/outcomes (651 lines)

MC-Specific Modules:
- GameModule v2: State machine + event subscriptions (updated)
- TrainBuilderModule: 3 wagons, 2-axis balance, performance malus (530 lines)
- ExpeditionModule: A→B expeditions, team management, events integration (641 lines)

Features:
- All modules hot-reload compatible (state preservation)
- Pure pub/sub architecture (zero direct coupling)
- 7 config files (resources, storage, combat, events, train, expeditions)
- 7 test suites (GameModuleTest: 12/12 PASSED)
- CMakeLists.txt updated for all modules + tests

Total: ~3,500 lines of production code + comprehensive tests

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 16:40:54 +08:00

94 lines
3.1 KiB
C++

#pragma once
#include <grove/IModule.h>
#include <grove/JsonDataNode.h>
#include <string>
#include <memory>
#include <chrono>
/**
* StorageModule - Game-agnostic save/load system
*
* GAME-AGNOSTIC CORE MODULE
* This module is shared between Mobile Command and WarFactory.
* DO NOT add game-specific logic here.
*
* Responsibilities:
* - Save game state to JSON files
* - Load game state from JSON files
* - Auto-save with configurable interval
* - Version management for save files
* - State collection from all modules via pub/sub
*
* Usage Examples:
*
* MOBILE COMMAND:
* - Saves: train state, expedition progress, timeline position
* - Load: Restores train composition, resources, crew
* - Auto-save: Every 5 minutes during gameplay
*
* WARFACTORY (Future):
* - Saves: factory state, production queues, research progress
* - Load: Restores assembly lines, resource stockpiles
* - Auto-save: Every 5 minutes during factory operation
*
* Pub/Sub Communication:
* - Subscribe: "game:request_save", "game:request_load"
* - Publish: "storage:save_complete", "storage:load_complete", "storage:save_failed"
* - Collect: "storage:collect_states" -> modules respond with their state
* - Restore: "storage:restore_state:{moduleName}" -> restore specific module
*/
class StorageModule : public grove::IModule {
public:
StorageModule();
~StorageModule() override = default;
// IModule interface
void setConfiguration(const grove::IDataNode& config, grove::IIO* io, grove::ITaskScheduler* scheduler) override;
void process(const grove::IDataNode& input) override;
void shutdown() override;
std::unique_ptr<grove::IDataNode> getState() override;
void setState(const grove::IDataNode& state) override;
const grove::IDataNode& getConfiguration() override;
std::unique_ptr<grove::IDataNode> getHealthStatus() override;
std::string getType() const override;
bool isIdle() const override;
private:
// Core save/load functionality
void saveGame(const std::string& filename = "");
void loadGame(const std::string& filename);
void autoSave();
// State collection via pub/sub
void collectModuleStates();
void restoreModuleStates(const grove::IDataNode& savedData);
// File operations
void ensureSaveDirectoryExists();
std::string getSaveFilePath(const std::string& filename) const;
std::string generateAutoSaveFilename() const;
// Message handlers
void handleMessages();
void onRequestSave(const grove::IDataNode& data);
void onRequestLoad(const grove::IDataNode& data);
void onModuleState(const grove::IDataNode& data);
// Member variables
grove::IIO* m_io = nullptr;
grove::ITaskScheduler* m_scheduler = nullptr;
grove::JsonDataNode m_config{"config"};
// Configuration
std::string m_savePath;
float m_autoSaveInterval; // seconds
int m_maxAutoSaves;
// State tracking
float m_timeSinceLastAutoSave;
std::map<std::string, std::unique_ptr<grove::IDataNode>> m_collectedStates;
bool m_collectingStates;
std::chrono::steady_clock::time_point m_collectionStartTime;
};