Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 31 additions & 19 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# AGENTS.md

## Orientation

For a high-level overview of the project's structure, data flow, and key components, please refer to [docs/architecture.md](docs/architecture.md). For detailed build instructions across all platforms, see [BUILD.md](BUILD.md).

## Coding Guidelines

To maintain consistency and avoid common pitfalls in this codebase, please follow these guidelines:

1. **Signal2 System:** Use the custom `Signal2` system (`src/global/Signal2.h`) for internal logic and performance-critical events. Use standard Qt signals primarily for UI components. Always use `Signal2Lifetime` for automatic disconnection.
2. **String Encoding:** **Never** use `QString::toStdString()`. It can cause encoding issues. Instead, use `mmqt::toStdStringUtf8()` from `src/global/TextUtils.h`.
3. **Atomic File Saving:** When saving files, follow the atomic pattern: `flush()` -> `io::fsync()` -> `file.close()` -> `io::rename()`. This prevents data corruption.
4. **Memory Management:**
* Avoid declaring `QObject` as value members if they are parented to their owner (e.g., `m_member(this)`). Use heap-allocated pointers instead.
* Rely on Qt's parent-child system for cleanup of UI components.
5. **Shortest Path Performance:** Use `thread_utils::parallel_for_each_tl` for relaxation phases in shortest path algorithms; it handles both single-threaded and parallel execution efficiently.

## Development Tips

### Tracing Data Flow
The `Proxy` pipeline (`src/proxy/proxy.cpp`) is the best place to start when tracing how data moves between the MUD and the user. Use `grep` to follow specific GMCP messages or Telnet commands through the pipeline.

### Testing
We use a variety of unit tests located in the `tests/` directory.
* To build and run all tests: `mkdir build && cd build && cmake .. && ninja && ctest`
* To run a specific test suite: `./build/tests/TestProxy` (replace `TestProxy` with the desired test executable name).

## Mandatory Build Guidelines

1. **Environment:** All builds **must** be performed on a **Linux** system.
Expand All @@ -12,31 +38,17 @@
To enable incremental, cached builds and reduce compilation time, `ccache` is **required**.

1. **Install:** Ensure `ccache` is installed on Linux.
* *Example:* `sudo apt-get install -y ccache`
2. **CMake Configuration:** The initial `cmake` command **must** use the Debug build type and include the ccache launcher flags:

```bash
cmake -B build/ \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
... [Other flags from BUILD.md]
cmake -B build/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache ...
```

---

## Code Style Application (Mandatory)

We use `clang-format-18` via Docker to ensure style consistency. Use the following command to automatically format your code.

1. **Directory:** Navigate to the Git root directory.
We use `clang-format-18` via Docker to ensure style consistency. Run this from the Git root:

2. **Execution:** Run this command to perform an in-place edit to all source files with the required style:

```bash
docker run --rm --platform linux/amd64 \
-v "$(pwd):$(pwd)" -w "$(pwd)" \
ghcr.io/jidicula/clang-format:18 \
-i --Werror --style=file \
$(find src tests -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.hpp')
```
```bash
docker run --rm --platform linux/amd64 -v "$(pwd):$(pwd)" -w "$(pwd)" ghcr.io/jidicula/clang-format:18 -i --Werror --style=file $(find src tests -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.hpp')
```
101 changes: 101 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# MMapper Architecture Overview

MMapper is a graphical mapping tool for the MUD game MUME. It acts as a bridge between the MUD server and the game client, providing an interactive map and enhanced features.

## 1. High-Level Data Flow (The Proxy Pipeline)

The `Proxy` class (`src/proxy/proxy.h`) manages the connection between the MUD server and the user's game client. It implements a pipeline for bidirectional data flow:

### From User to MUD
`UserSocket` -> `UserTelnet` -> `TelnetLineFilter` -> `AbstractParser` (UserInputParser) -> `MudTelnet` -> `MudSocket`

* **UserSocket**: Raw TCP/WebSocket connection from the game client.
* **UserTelnet**: Handles Telnet protocol (negotiation, IAC sequences).
* **TelnetLineFilter**: Buffers raw bytes into lines.
* **AbstractParser**: Processes user commands (e.g., `.map`, `.mark`). Commands not handled by MMapper are forwarded to `MudTelnet`.

### From MUD to User
`MudSocket` -> `MudTelnet` -> `TelnetLineFilter` -> `MpiFilter` -> {`RemoteEdit` or `MumeXmlParser` (MudParser)} -> `UserTelnet` -> `UserSocket`

* **MudSocket**: Raw connection to MUME.
* **MudTelnet**: Handles Telnet protocol and GMCP (Game Master Client Protocol).
* **MpiFilter**: Originally for the legacy MPI protocol; now primarily used to route out-of-band "MUME.Client" GMCP messages for remote editing or viewing.
* **MumeXmlParser**: Parses game data (vitals, room info, exits) to update the map and internal state.

## 2. Key Components

### PathMachine (`src/pathmachine/`)
The core auto-mapping algorithm. It reconciles game events with the map database.
* **States**:
* **APPROVED**: Confident of location; uses "matching tolerance" for room descriptions.
* **EXPERIMENTING**: Ambiguous location; tracks multiple hypothesis paths and prunes them based on likelihood factors (distance, new rooms, etc.).
* **SYNCING**: Lost track; performs a global search of room descriptions to find a match.

### Map and World State (`src/map/`, `src/mapdata/`)
* **MapData**: Primary owner of the map state, including the `World` graph and `MarkerList`.
* **World**: Graph representation of rooms and exits. Supports multiple "layers" for pseudo-3D representation.
* **SpatialDb**: Manages room-to-coordinate mappings using an immutable unordered map for fast lookups.
* **ShortestPath**: Implements a Dijkstra-based search algorithm for navigation and pathfinding.
* **MapHistory**: Manages undo/redo operations by tracking `Change` objects.

### Map Storage (`src/mapstorage/`)
* **Formats**: Supports MMP (binary), JSON, XML, and Pandora.
* **Load/Save**: Uses `MapSource` and `MapDestination` abstractions.
* **Atomic Save**: Uses `FileSaver` to ensure data integrity via flush/sync/rename.

### Rendering Architecture (`src/display/`, `src/opengl/`)
MMapper uses a modern rendering pipeline focused on cross-platform compatibility (Desktop OpenGL & WebGL).
* **MapCanvas**: A `QOpenGLWindow` that renders to an internal Framebuffer Object (FBO).
* **FBO & Blitting**: Rendering is done to an FBO (optionally multisampled), which is then resolved and blitted to the default framebuffer via a full-screen triangle blit shader (`Functions::blitFboToDefault`).
* **OpenGLProber**: Probes hardware capabilities by creating temporary OpenGL contexts to select the best rendering backend.
* **Unified Shaders**: Shaders (`src/resources/shaders/`) are written in a unified format for GL 3.3 and GLES 3.0/WebGL 2.0. The appropriate `#version` and precision headers are prepended at runtime via `Functions::getShaderVersion()`.
* **Shared Buffers**: Uses Uniform Buffer Objects (UBOs) for efficient sharing of global state (colors, projection matrices) across shaders.

### Command & Syntax System (`src/syntax/`, `src/parser/`)
* **AbstractParser**: The central dispatcher for user commands.
* **Syntax Tree**: Uses a dedicated syntax parser (`src/syntax/`) to define and validate complex command structures.

### MUD Integration & World Tracking
* **Remote Edit/View**: Special functionality to open dedicated editor or viewer windows for content like maps or room descriptions. This uses the `MUME.Client` GMCP namespace.
* **Group Management**: Tracks group member vitals and map positions via GMCP.
* **Adventure Tracker**: Monitors XP gains, session duration, and character status.
* **MumeClock**: Tracks Middle-earth time, moon phases, and seasons.
* **GameObserver**: Centralized hub for world-state signals.

## 3. Core Design Patterns

### Signal2 System (`src/global/Signal2.h`)
A lightweight, high-performance alternative to Qt signals for core logic.
* **Signal2Lifetime**: Required for safe disconnection.
* **WeakHandle**: Prevents crashes when referencing objects across threads or lifetimes.

### Strategy Pattern
Used in `PathProcessor` (pathmachine), `MapStorage` (formats), and `Functions` (rendering backends).

### Pipeline Interfaces
The `Proxy` uses nested `Outputs` structs (e.g., `AbstractParserOutputs`) to decouple components and enforce explicit data flow.

## 4. Common Developer Tasks

### Adding a User Command
1. Define the command syntax in `src/parser/AbstractParser.cpp`.
2. Add a callback in `AbstractParser::initSpecialCommandMap`.
3. Implement the logic in `AbstractParser`.

### Handling a New GMCP Message
1. Add the message module to `src/proxy/GmcpModule.h`.
2. Implement parsing in `MumeXmlParser::slot_parseGmcpInput` or `Mmapper2Group::slot_parseGmcpInput`.

### Creating a New Shader
1. Add `.glsl` files to `src/resources/shaders/`.
2. Declare the shader program struct in `src/opengl/legacy/Shaders.h`.
3. Implement uniform setup and loading in `src/opengl/legacy/Shaders.cpp`.

## 5. Glossary

* **GMCP**: Game Master Client Protocol. A JSON-based protocol over Telnet used for out-of-band data. See [MUME's GMCP documentation](https://mume.org/help/generic_mud_communication_protocol) for supported modules.
* **MUME.Client**: A GMCP namespace used for remote editing and viewing of game content (successor to the legacy MPI protocol).
* **IAC**: Interpret As Command. Telnet escape character (`0xFF`).
* **Vitals**: Character status data (HP, Mana, Moves).
* **FBO**: Framebuffer Object. An off-screen rendering target.
* **UBO**: Uniform Buffer Object. A buffer for sharing uniform data between shaders.
Loading