> For the complete documentation index, see [llms.txt](https://azuriohs-organization.gitbook.io/r-type/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://azuriohs-organization.gitbook.io/r-type/subsystems/our-subsystems/messaging-passing-interface.md).

# Message passing interface

## Table of Contents

* [Introduction](#introduction)
* [Overview](#overview)
* [Architecture](#architecture)
* [Getting Started](#getting-started)
* [Core Components](#core-components)
  * [Event System](#event-system)
  * [Message Passing Interface](#message-passing-interface)
* [Event Registration](#event-registration)
* [Event Triggering](#event-triggering)
* [Event Queuing](#event-queuing)
* [Advanced Features](#advanced-features)
* [Examples](#examples)
* [Best Practices](#best-practices)
* [Troubleshooting](#troubleshooting)

***

## Introduction

The Message Passing Interface (MPI) is a C++ event-driven messaging subsystem designed for the R-Type game engine. It provides a decoupled communication mechanism between different parts of the application through a publish-subscribe pattern.

This MPI subsystem is designed as a modular library that can be dynamically loaded into the R-Type game engine, following the plugin architecture pattern. It implements the `IMessagePassingInterface` interface from the common engine subsystem, allowing for easy swapping between different messaging implementations.

***

## Overview

### Features

* **Event-Driven Architecture**: Decoupled communication through events
* **Type-Safe Events**: Type-safe event system using `std::type_index`
* **Thread-Safe**: Mutex-protected operations for multi-threaded environments
* **Event Queuing**: Support for immediate and deferred event processing
* **Event Redirection**: Redirect events from one type to another
* **Metadata Support**: Optional metadata attachment to events
* **Multiple Listeners**: Multiple callbacks per event type

### Dependencies

* **C++20 Standard Library**: Required for `std::type_index`, `std::optional`, `std::any`
* **Common Engine**: Depends on the common engine interfaces

### Build Requirements

* CMake 3.16.0 or higher
* C++20 compiler

***

## Architecture

### Module Structure

The MPI subsystem follows a simple, focused architecture:

```
MPI Module (Entry Point)
├── Event System
│   ├── IEvent (Interface)
│   └── AEvent (Base Class)
└── Message Passing Interface
    ├── IMessagePassingInterface (Interface)
    └── MessagePassingInterface (Implementation)
        ├── Event Listeners (unordered_map)
        ├── Event Queue
        └── Thread Safety (mutex)
```

### Entry Point

The module exports an entry point function that returns a `MessagePassingInterface` instance:

```cpp
extern "C" Subsystems::MPI::MessagePassingInterface *entryPoint(void);
```

This allows the engine to dynamically load the MPI library at runtime.

***

## Getting Started

### Building the Module

1. **Configure CMake**:

```bash
cd lib/MPI/V1
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
```

2. **Build**:

```bash
cmake --build build
```

The compiled library (`libmpi-v1.dylib` on macOS, `.so` on Linux, `.dll` on Windows) will be placed in the `lib/` directory.

### Basic Usage

```cpp
#include "Subsystems/MPI/IMessagePassingInterface.hpp"
#include "Subsystems/MPI/IEvent.hpp"
#include "YourEvent.hpp"

// Create MPI instance (usually loaded dynamically)
auto mpi = std::make_unique<Subsystems::MPI::MessagePassingInterface>();

// Register event listener
mpi->On(typeid(YourEvent), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    const auto& yourEvent = static_cast<const YourEvent&>(event);
    // Handle the event
    std::cout << "Event received: " << yourEvent.GetName() << std::endl;
});

// Trigger an event
YourEvent event("Test Event");
mpi->TriggerEvent(event);

// Or queue for later processing
auto queuedEvent = std::make_unique<YourEvent>("Queued Event");
mpi->QueueEvent(std::move(queuedEvent));

// Process queued events
mpi->ProcessEvents();
```

***

## Core Components

### Event System

The event system is based on two main interfaces:

#### IEvent

The `IEvent` interface is the base interface for all events in the system.

**Key Methods:**

* `GetName()`: Returns the name of the event as a string

**Example:**

```cpp
class CustomEvent : public Subsystems::MPI::IEvent {
public:
    std::string GetName() const override {
        return "CustomEvent";
    }
};
```

#### AEvent

The `AEvent` class is an abstract base class that provides a convenient implementation of `IEvent`.

**Key Methods:**

* Constructor: `AEvent(const std::string name)`
* `GetName()`: Returns the event name

**Example:**

```cpp
#include "Subsystems/MPI/AEvent.hpp"

class EntityCreated : public Subsystems::MPI::AEvent {
public:
    EntityCreated(const std::string& entityName, std::uint32_t id)
        : AEvent("EntityCreated"), _entityName(entityName), _id(id) {}

    std::string GetEntityName() const { return _entityName; }
    std::uint32_t GetId() const { return _id; }

private:
    std::string _entityName;
    std::uint32_t _id;
};
```

### Message Passing Interface

The `MessagePassingInterface` class is the core component that manages event registration, triggering, and processing.

**Key Methods:**

* `On(eventType, callback)`: Register a callback for an event type
* `On(eventType, redirection)`: Redirect one event type to another
* `Off(eventType)`: Unregister all callbacks for an event type
* `TriggerEvent(event, metadata)`: Trigger an event immediately
* `QueueEvent(event, metadata)`: Queue an event for later processing
* `ProcessEvents()`: Process all queued events

**Thread Safety:**

All operations are protected by a mutex, making the MPI thread-safe for concurrent access.

***

## Event Registration

### Registering Callbacks

You can register one or more callbacks for a specific event type using the `On()` method:

```cpp
auto mpi = std::make_unique<Subsystems::MPI::MessagePassingInterface>();

// Register a callback
mpi->On(typeid(EntityCreated), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    const auto& entityEvent = static_cast<const EntityCreated&>(event);
    std::cout << "Entity created: " << entityEvent.GetName() << std::endl;
});

// Register another callback for the same event type
mpi->On(typeid(EntityCreated), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    const auto& entityEvent = static_cast<const EntityCreated&>(event);
    std::cout << "Entity ID: " << entityEvent.GetId() << std::endl;
});
```

Both callbacks will be invoked when an `EntityCreated` event is triggered.

### Event Redirection

You can redirect events from one type to another, sharing the same callbacks:

```cpp
// Register callbacks for TargetEvent
mpi->On(typeid(TargetEvent), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    // Handle TargetEvent
});

// Redirect SourceEvent to TargetEvent
mpi->On(typeid(SourceEvent), typeid(TargetEvent));

// Now SourceEvent will trigger the same callbacks as TargetEvent
```

### Unregistering Callbacks

To remove all callbacks for an event type:

```cpp
mpi->Off(typeid(EntityCreated));
```

This removes all registered callbacks for the specified event type.

***

## Event Triggering

### Immediate Triggering

Use `TriggerEvent()` to trigger an event immediately. All registered callbacks are invoked synchronously:

```cpp
EntityCreated event("Player", 123);
mpi->TriggerEvent(event);
```

### Triggering with Metadata

You can attach optional metadata to events:

```cpp
EntityCreated event("Player", 123);
std::any metadata = std::make_any<std::string>("Additional context");
mpi->TriggerEvent(event, metadata);

// In callback
mpi->On(typeid(EntityCreated), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    if (metadata.has_value()) {
        try {
            auto context = std::any_cast<std::string>(metadata.value());
            std::cout << "Context: " << context << std::endl;
        } catch (const std::bad_any_cast& e) {
            // Handle invalid cast
        }
    }
});
```

### Type Safety

Events are identified by their C++ type using `std::type_index`. This ensures type safety:

```cpp
// This will only match EntityCreated events
mpi->On(typeid(EntityCreated), callback);

// Different events won't match
EntityDeleted deleted("Player");
mpi->TriggerEvent(deleted); // Won't trigger EntityCreated callbacks
```

***

## Event Queuing

### Queueing Events

For deferred event processing, use `QueueEvent()`:

```cpp
auto event = std::make_unique<EntityCreated>("Player", 123);
mpi->QueueEvent(std::move(event));

// Event is queued but not processed yet
// Call ProcessEvents() to process all queued events
```

**Note:** `QueueEvent()` takes ownership of the event via `std::unique_ptr`.

### Processing Queued Events

Call `ProcessEvents()` to process all queued events:

```cpp
// Main loop
while (gameRunning) {
    // ... game logic ...

    // Process all queued events
    mpi->ProcessEvents();
}
```

All queued events are processed in FIFO (First In, First Out) order.

### Queue with Metadata

You can queue events with metadata:

```cpp
auto event = std::make_unique<EntityCreated>("Player", 123);
std::any metadata = std::make_any<int>(42);
mpi->QueueEvent(std::move(event), metadata);
```

***

## Advanced Features

### Multiple Event Types

Register callbacks for multiple event types:

```cpp
mpi->On(typeid(EntityCreated), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    // Handle EntityCreated
});

mpi->On(typeid(EntityDeleted), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    // Handle EntityDeleted
});
```

### Event Chain

Create event chains by triggering events from callbacks:

```cpp
mpi->On(typeid(EntityCreated), [&mpi](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    // Process EntityCreated
    const auto& created = static_cast<const EntityCreated&>(event);

    // Trigger a follow-up event
    EntityInitialized initialized(created.GetId());
    mpi->TriggerEvent(initialized);
});
```

***

## Examples

### Complete Event System Setup

```cpp
#include "Subsystems/MPI/IMessagePassingInterface.hpp"
#include "Subsystems/MPI/AEvent.hpp"
#include <iostream>
#include <memory>

// Define custom events
class PlayerJoined : public Subsystems::MPI::AEvent {
public:
    PlayerJoined(const std::string& playerName)
        : AEvent("PlayerJoined"), _playerName(playerName) {}

    std::string GetPlayerName() const { return _playerName; }
private:
    std::string _playerName;
};

class GameStarted : public Subsystems::MPI::AEvent {
public:
    GameStarted() : AEvent("GameStarted") {}
};

// Game system
class GameSystem {
public:
    GameSystem(Subsystems::MPI::IMessagePassingInterface* mpi) : _mpi(mpi) {
        // Register event listeners
        _mpi->On(typeid(PlayerJoined), [this](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
            const auto& playerEvent = static_cast<const PlayerJoined&>(event);
            std::cout << "Player joined: " << playerEvent.GetPlayerName() << std::endl;

            // Start game when 4 players join
            _playerCount++;
            if (_playerCount >= 4) {
                GameStarted started;
                _mpi->TriggerEvent(started);
            }
        });

        _mpi->On(typeid(GameStarted), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
            std::cout << "Game started!" << std::endl;
        });
    }

    void JoinPlayer(const std::string& name) {
        PlayerJoined event(name);
        _mpi->TriggerEvent(event);
    }

private:
    Subsystems::MPI::IMessagePassingInterface* _mpi;
    int _playerCount = 0;
};

// Usage
int main() {
    auto mpi = std::make_unique<Subsystems::MPI::MessagePassingInterface>();
    GameSystem game(mpi.get());

    game.JoinPlayer("Alice");
    game.JoinPlayer("Bob");
    game.JoinPlayer("Charlie");
    game.JoinPlayer("David"); // Will trigger GameStarted

    return 0;
}
```

### Event Queuing Pattern

```cpp
class EventProcessor {
public:
    EventProcessor(Subsystems::MPI::IMessagePassingInterface* mpi) : _mpi(mpi) {}

    void QueueEntityCreation(const std::string& name, std::uint32_t id) {
        auto event = std::make_unique<EntityCreated>(name, id);
        _mpi->QueueEvent(std::move(event));
    }

    void ProcessFrame() {
        // Process all queued events at the end of the frame
        _mpi->ProcessEvents();
    }
};

// In game loop
EventProcessor processor(mpi.get());

while (gameRunning) {
    // Game logic
    if (shouldCreateEntity) {
        processor.QueueEntityCreation("Enemy", 456);
    }

    // Process events at end of frame
    processor.ProcessFrame();
}
```

### Event Redirection Pattern

```cpp
// Define base event
class BaseEvent : public Subsystems::MPI::AEvent {
public:
    BaseEvent() : AEvent("BaseEvent") {}
};

// Define specific events
class NetworkEvent : public Subsystems::MPI::AEvent {
public:
    NetworkEvent() : AEvent("NetworkEvent") {}
};

class LocalEvent : public Subsystems::MPI::AEvent {
public:
    LocalEvent() : AEvent("LocalEvent") {}
};

// Setup
mpi->On(typeid(BaseEvent), [](const Subsystems::MPI::IEvent& event, std::optional<std::any> metadata) {
    // Handle base event
});

// Redirect specific events to base event
mpi->On(typeid(NetworkEvent), typeid(BaseEvent));
mpi->On(typeid(LocalEvent), typeid(BaseEvent));

// Now both NetworkEvent and LocalEvent will trigger BaseEvent callbacks
NetworkEvent netEvent;
mpi->TriggerEvent(netEvent); // Will trigger BaseEvent callbacks
```

***

## Best Practices

### Event Design

* **Use AEvent base class**: Inherit from `AEvent` for convenience
* **Descriptive names**: Use clear, descriptive event names
* **Keep events simple**: Events should be data containers, not complex objects
* **Immutable events**: Make events immutable after construction

### Performance

* **Use typeid() sparingly**: Cache `std::type_index` if used frequently
* **Process events at fixed intervals**: Call `ProcessEvents()` at consistent points (e.g., end of frame)
* **Minimize event size**: Keep events lightweight
* **Batch processing**: Queue multiple events and process them together

### Thread Safety

* **Single MPI instance**: Use one MPI instance per application or subsystem
* **Don't hold locks**: The MPI manages its own locks, don't hold additional locks in callbacks
* **Avoid blocking in callbacks**: Keep callbacks short to avoid blocking other threads

### Memory Management

* **Smart pointers**: Use `std::unique_ptr` when queueing events
* **Avoid circular references**: Be careful with lambdas capturing MPI or event objects
* **Clean up listeners**: Call `Off()` when listeners are no longer needed

### Event Patterns

* **Single responsibility**: Each event should represent one concept
* **Event composition**: Use metadata for additional context rather than creating many event types
* **Documentation**: Document event structures and when they're triggered

***

## Troubleshooting

### Common Issues

**Events not triggering:**

* Verify event types match exactly: `typeid(EventType)` must match
* Check that callbacks are registered before events are triggered
* Ensure `ProcessEvents()` is called if using queued events

**Memory leaks:**

* Ensure queued events are processed (call `ProcessEvents()`)
* Clean up event listeners with `Off()` when done
* Check for circular references in lambdas

**Thread safety issues:**

* The MPI is thread-safe, but be careful with shared state in callbacks
* Avoid modifying listener map while processing events
* Use synchronization primitives for shared data outside MPI

**Type mismatch errors:**

* Use exact type when registering: `typeid(ExactEventType)`
* Ensure event class matches registered type
* Cast carefully in callbacks: `static_cast<const YourEvent&>(event)`

**Performance problems:**

* Too many callbacks registered for one event type
* Events processed too frequently
* Large event objects causing memory pressure

***

## API Reference

For detailed API documentation, refer to the header files:

* `IMessagePassingInterface.hpp`: Main MPI interface
* `IEvent.hpp`: Event interface
* `AEvent.hpp`: Abstract event base class
* `MessagePassingInterface.hpp`: MPI implementation

***

## Version Information

* **Version**: 1.0.0
* **Build System**: CMake 3.16.0+
* **C++ Standard**: C++20
* **Platform Support**: macOS, Linux, Windows

***

## License

This MPI subsystem is part of the R-Type project (EPITECH, 2025).

***

## Contributing

When contributing to the MPI subsystem:

1. Follow the existing code style
2. Add documentation for new features
3. Update this documentation file
4. Test thread safety in multi-threaded scenarios
5. Ensure backward compatibility with the `IMessagePassingInterface` interface
6. Add unit tests for new functionality

***

*Last Updated: 2025*
