## Breaking Change
IIO API redesigned from manual pull+if-forest to callback dispatch.
All modules must update their subscribe() calls to pass handlers.
### Before (OLD API)
```cpp
io->subscribe("input:mouse");
void process(...) {
while (io->hasMessages()) {
auto msg = io->pullMessage();
if (msg.topic == "input:mouse") {
handleMouse(msg);
} else if (msg.topic == "input:keyboard") {
handleKeyboard(msg);
}
}
}
```
### After (NEW API)
```cpp
io->subscribe("input:mouse", [this](const Message& msg) {
handleMouse(msg);
});
void process(...) {
while (io->hasMessages()) {
io->pullAndDispatch(); // Callbacks invoked automatically
}
}
```
## Changes
**Core API (include/grove/IIO.h)**
- Added: `using MessageHandler = std::function<void(const Message&)>`
- Changed: `subscribe()` now requires `MessageHandler` callback parameter
- Changed: `subscribeLowFreq()` now requires `MessageHandler` callback
- Removed: `pullMessage()`
- Added: `pullAndDispatch()` - pulls and auto-dispatches to handlers
**Implementation (src/IntraIO.cpp)**
- Store callbacks in `Subscription.handler`
- `pullAndDispatch()` matches topic against ALL subscriptions (not just first)
- Fixed: Regex pattern compilation supports both wildcards (*) and regex (.*)
- Performance: ~1000 msg/s throughput (unchanged from before)
**Files Updated**
- 31 test/module files migrated to callback API (via parallel agents)
- 8 documentation files updated (DEVELOPER_GUIDE, USER_GUIDE, module READMEs)
## Bugs Fixed During Migration
1. **pullAndDispatch() early return bug**: Was only calling FIRST matching handler
- Fix: Loop through ALL subscriptions, invoke all matching handlers
2. **Regex pattern compilation bug**: Pattern "player:.*" failed to match
- Fix: Detect ".*" in pattern → use as regex, otherwise escape and convert wildcards
## Testing
✅ test_11_io_system: PASSED (IIO pub/sub, pattern matching, batching)
✅ test_threaded_module_system: 6/6 PASSED
✅ test_threaded_stress: 5/5 PASSED (50 modules, 100x reload, concurrent ops)
✅ test_12_datanode: PASSED
✅ 10 TopicTree scenarios: 10/10 PASSED
✅ benchmark_e2e: ~1000 msg/s throughput
Total: 23+ tests passing
## Performance Impact
No performance regression from callback dispatch:
- IIO throughput: ~1000 msg/s (same as before)
- ThreadedModuleSystem: Speedup ~1.0x (barrier pattern expected)
## Migration Guide
For all modules using IIO:
1. Update subscribe() calls to include handler lambda
2. Replace pullMessage() loops with pullAndDispatch()
3. Move topic-specific logic from if-forest into callbacks
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| architecture | ||
| implementation | ||
| performance_reports | ||
| plans | ||
| coding_guidelines.md | ||
| DEVELOPER_GUIDE.md | ||
| FEATURES.md | ||
| PLAN_BGFX_RENDERER.md | ||
| PROMPT_UI_MODULE_PHASE6.md | ||
| README.md | ||
| THREADED_MODULE_SYSTEM_VALIDATION.md | ||
| UI_ARCHITECTURE.md | ||
| UI_MODULE_DEMO.md | ||
| UI_MODULE_PHASE2_COMPLETE.md | ||
| UI_MODULE_PHASE3_COMPLETE.md | ||
| UI_MODULE_PHASE6_PROGRESS.md | ||
| UI_MODULE_PHASE7_COMPLETE.md | ||
| UI_RENDERING.md | ||
| UI_TOPICS.md | ||
| UI_WIDGETS.md | ||
| USER_GUIDE.md | ||
GroveEngine Documentation
Overview
GroveEngine is a modular game engine architecture designed for distributed systems and hot-reload development. It provides a clean separation between business logic (modules) and infrastructure (engine, IO, scheduling).
Architecture Documents
Core Systems
-
Data Tree System - Unified config/data/runtime management
- IDataNode/IDataValue/IDataTree interfaces
- JSON backend implementation
- Hot-reload and persistence
- Distributed configuration synchronization
-
Modular Architecture - Module system design
- IModule interface and constraints
- IModuleSystem execution strategies
- Hot-reload workflow
- Claude Code optimization
-
Claude Code Integration - AI development workflow
- Micro-context development
- Hot-reload for rapid iteration
- Module development best practices
Quick Start
Creating a Module
#include <grove/IModule.h>
#include <grove/IDataNode.h>
class TankModule : public IModule {
private:
IIO* m_io;
int m_armor;
double m_speed;
public:
void setConfiguration(const IDataNode& config, IIO* io, ITaskScheduler* scheduler) override {
m_io = io;
m_armor = config.getInt("armor", 100);
m_speed = config.getDouble("speed", 5.0);
}
void process(const IDataNode& input) override {
// Game logic here
// Save state via IIO
auto state = createDataNode({
{"armor", m_armor},
{"speed", m_speed}
});
m_io->publish("save:tank:state", std::move(state));
}
std::unique_ptr<IDataNode> getState() override {
return createDataNode({
{"armor", m_armor},
{"speed", m_speed}
});
}
void setState(const IDataNode& state) override {
m_armor = state.getInt("armor", 100);
m_speed = state.getDouble("speed", 5.0);
}
std::string getType() const override { return "tank"; }
};
Using the Data Tree
#include <grove/DataTreeFactory.h>
// Create tree
auto tree = DataTreeFactory::create("json", "./gamedata");
// Access configuration (read-only)
auto configRoot = tree->getConfigRoot();
auto tankConfig = configRoot->getChild("tanks")->getChild("heavy");
int armor = tankConfig->getInt("armor");
// Access persistent data (read-write)
auto dataRoot = tree->getDataRoot();
auto progress = dataRoot->getChild("campaign")->getChild("progress");
progress->setData(createDataNode({{"level", 5}}));
tree->saveData();
// Hot-reload config
if (tree->reloadIfChanged()) {
// Config changed, refresh modules
}
Key Concepts
Module System
- Modules: 200-300 line business logic units
- IModuleSystem: Execution strategy (Sequential, Threaded, Distributed)
- Hot-reload: Replace modules without restarting
- State preservation: getState/setState for seamless updates
Data Management
- config/: Read-only game configuration (hot-reload, distributed)
- data/: Persistent player data (local saves)
- runtime/: Temporary state (never saved)
Communication
- IIO: Pub/sub messaging between modules
- ITaskScheduler: Delegate heavy computation
- Save pattern: Modules publish "save:*" messages, Engine persists
Distribution
- Coordinator: Master config with hot-reload
- Engines: Local replicas, synchronized config
- Isolation: Each Engine has independent data/
Design Principles
- Interface-based: Work with abstractions (IDataNode, not JsonDataNode)
- Backend-agnostic: Swap implementations without code changes
- Minimal coupling: Modules communicate only via IIO
- Hot-reload first: Development optimized for instant feedback
- Distribution-ready: Config sync, data isolation built-in
Project Status
Implemented ✅
- Complete IDataNode/IDataTree system
- JSON backend (JsonDataValue, JsonDataNode, JsonDataTree)
- Hot-reload for config files
- Save/load for persistent data
- Pattern matching and property queries
- SHA256 hashing for validation
In Progress 🚧
- Coordinator synchronization implementation
- Module system integration with DataTree
- Example modules and tests
Planned 📋
- Binary format backend
- Database backend
- Network synchronization protocol
- Schema validation
- Migration system
Contributing
When adding new features:
- Start with interface definition (.h file)
- Add documentation to this folder
- Implement concrete class
- Update architecture docs
- Write usage examples
Further Reading
Last Updated: 2025-10-28 Engine Version: 1.0.0