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
4 changes: 4 additions & 0 deletions docs/developer/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Developer",
"position": 3
}
29 changes: 29 additions & 0 deletions docs/developer/advanced-solvers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
sidebar_position: 3
---

# Advanced Solver Architectures

Dungeons Guide employs several sophisticated algorithms to solve the most complex puzzles and optimization problems in dungeons. This document provides a high-level overview of the two main advanced solver architectures. For a deeper, more technical dive into each component, please see the detailed pages in the **[Core Systems](./core-systems/waterboard-solver.md)** section.

## 1. Waterboard Puzzle Solver

The Waterboard puzzle is a complex state-space search problem. The mod solves this by using a **simulated annealing** algorithm, which is implemented in native C++ for maximum performance. This probabilistic technique allows the solver to efficiently search the vast space of possible lever flips and timings to find a high-quality solution.

- **[Read the detailed Waterboard Solver documentation...](./core-systems/waterboard-solver.md)**

## 2. Secret Route Pathfinder

The "Secret Finder" feature is a powerful route optimization engine that calculates the most efficient path to collect all secrets and complete all necessary tasks within a room. This system is built on several interconnected components.

- **The ActionDAG:** The entire problem of clearing a room is first modeled as a **D**irected **A**cyclic **G**raph of all necessary actions and their dependencies. This allows the system to understand complex prerequisites, such as needing to flip a lever to unlock a secret.
- **[Read the detailed ActionDAG documentation...](./core-systems/action-dag.md)**

- **The TSP Solver:** Finding the best path through the ActionDAG is a **T**raveling **S**alesperson **P**roblem. The mod uses a multi-stage solver, with its core logic implemented in native C++ for performance, to find the most efficient route.
- **[Read the detailed TSP Solver documentation...](./core-systems/tsp-solver.md)**

- **Pre-calculation and Caching:** To ensure the TSP solver can run in real-time without causing lag, all pathfinding costs are calculated offline by developers and consolidated into a single cache file for each room. At runtime, the solver reads from this in-memory cache for instant results.
- **[Read the detailed Pre-calculation and Caching documentation...](./core-systems/pre-calculation.md)**

- **Code Example:** To see how these systems are tied together by a trigger feature, refer to the Smart Route example.
- **[Read the Smart Route Example...](./core-systems/smart-route-example.md)**
57 changes: 57 additions & 0 deletions docs/developer/code-structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
sidebar_position: 1
---

# Code Structure and Architecture

This document provides a high-level overview of the Dungeons Guide mod's architecture. For a more detailed look at the core systems, please see the following pages:

- **[Core Data Model: Blueprints and Instances](./core-systems/data-model.md)**
- **[Coordinates and Room Detection](./core-systems/coordinates-and-room-detection.md)**
- **[Dungeon State Management](./dungeon-state-management.md)**
- **[Advanced Solver Architectures](./advanced-solvers.md)**

## High-Level Data Flow

The mod's architecture is designed around a one-way data flow, ensuring that the state remains consistent and predictable.

1. **Raw Game Events:** The process begins with raw events from Minecraft, such as chat messages, map data updates, entity spawns, and world ticks.
2. **Listeners (`DungeonListener`, etc.):** These classes are registered with the Minecraft Forge event bus. Their sole purpose is to capture these raw game events.
3. **`DungeonContext` Update:** The listeners take the raw event data and translate it into meaningful state changes within the central `DungeonContext`. For example, a chat message about a puzzle failure updates a flag in the context.
4. **`RoomProcessor` Logic:** The various `RoomProcessor` instances (for puzzles, boss fights, etc.) continuously monitor the `DungeonContext`. Based on the state in the context, they run their own logic to determine the current state of the puzzle or room (e.g., which blaze to shoot next). The results of this logic are also stored back into the `DungeonContext` or within the processor itself.
5. **Feature Logic (`AbstractFeature`):** The individual features that the user sees (like HUD elements or solvers) are the final step. They read the processed state from the `DungeonContext` and the `RoomProcessors`. They do not modify the state themselves; they are purely for presentation.
6. **User Display:** The feature then uses this information to render waypoints, display HUD text, or highlight entities, providing the final output to the user.

This unidirectional flow prevents circular dependencies and makes the system easier to debug and reason about. Data flows from the game, is processed into a central state, and then displayed by features.

## Package Overview

- **`kr.syeyoung.dungeonsguide.mod`**: The root package for the mod. It contains the main mod class, `DungeonsGuide.java`, which is the entry point for the mod and handles initialization and event registration.

- **`kr.syeyoung.dungeonsguide.mod.chat`**: This package contains classes for processing and sending chat messages.

- **`kr.syeyoung.dungeonsguide.mod.commands`**: This package contains the implementation for all of the mod's chat commands (e.g., `/dg`, `/reparty`).

- **`kr.syeyoung.dungeonsguide.mod.config`**: This package handles loading and saving the mod's configuration. The `Config.java` class is responsible for serializing and deserializing the configuration to and from a JSON file. Individual features define their own configuration parameters.

- **`kr.syeyoung.dungeonsguide.mod.cosmetics`**: This package contains features related to player cosmetics, such as custom nickname colors, prefixes, and player models.

- **`kr.syeyoung.dungeonsguide.mod.discord`**: This package contains all the code for Discord Rich Presence integration, including handling party invites and displaying friend activity.

- **`kr.syeyoung.dungeonsguide.mod.dungeon`**: This is a core package that contains the logic for tracking the player's state within a dungeon. This includes parsing the dungeon layout, tracking room completion, and managing boss fight mechanics.

- **`kr.syeyoung.dungeonsguide.mod.events`**: This package defines a custom event system that is used throughout the mod to communicate between different components.

- **`kr.syeyoung.dungeonsguide.mod.features`**: This package contains the base classes and registry for all of the mod's features. Each feature is a subclass of `AbstractFeature` and is registered with the `FeatureRegistry`. This allows for a modular and extensible system for adding new features.

- **`kr.syeyoung.dungeonsguide.mod.gui`**: This package contains the graphical user interface (GUI) components for the mod, including the main configuration GUI and various HUD elements.

- **`kr.syeyoung.dungeonsguide.mod.overlay`**: This package contains the system for rendering HUD overlays on the screen.

- **`kr.syeyoung.dungeonsguide.mod.party`**: This package contains the logic for managing the player's party, including repartying and handling party invites.

- **`kr.syeyoung.dungeonsguide.mod.pathfinding`**: This package contains pathfinding algorithms used by some of the solvers, such as the ice fill and silverfish solvers.

- **`kr.syeyoung.dungeonsguide.mod.player`**: This package is responsible for tracking player data and statistics.

- **`kr.syeyoung.dungeonsguide.mod.utils`**: This package contains various utility classes that are used throughout the mod.
4 changes: 4 additions & 0 deletions docs/developer/core-systems/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Core Systems",
"position": 4
}
31 changes: 31 additions & 0 deletions docs/developer/core-systems/action-dag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
sidebar_position: 3
---

# The ActionDAG: Modeling Complex Tasks

The core of the Secret Finder and other complex route-planning features is the **ActionDAG**, a **D**irected **A**cyclic **G**raph of actions. This data structure provides a powerful and flexible way to represent all the possible tasks and their dependencies required to clear a dungeon room. Instead of a simple list of locations, the ActionDAG models the entire problem as a graph, which can then be solved to find the most efficient solution.

## A Recursive Construction Process

The power of the system lies in how the `ActionDAG` is constructed. The logic is not centralized in a single, monolithic class; it is **distributed throughout the `AbstractAction` subclasses themselves** in an elegant, recursive process.

The process begins when a feature requests a path to achieve a high-level goal, such as getting a specific secret. This creates an `ActionRoute`, which in turn instantiates an `ActionDAGBuilder` and calls its `requires()` method with a high-level action, for example: `requires(new ActionChangeState("secret_chest_1", "found"))`.

This is where the recursion starts. The builder adds this top-level `ActionChangeState` node to the graph and then calls the `buildActionDAG()` method on the node it just added. The `ActionChangeState` class's implementation of this method knows what it means to "find" a chest: you must first move to it, and then click on it. It then uses the builder it was passed to add its own, lower-level dependencies, such as `builder.requires(new ActionMove(...))` and `builder.requires(new ActionClick(...))`. This process continues, with each action being responsible for defining its own prerequisites, until it reaches "atomic" actions like `ActionMove`, whose `buildActionDAG()` methods are empty, which terminates that branch of the recursion.

## Modeling Choices: The Three Connection Types

The `ActionDAGBuilder` supports three distinct ways to define the relationship between a parent node and its prerequisites, giving it incredible flexibility.

The most common connection is made with the **`requires()`** method, which creates a standard "AND" dependency. This is a list of nodes that must all be completed before the current node can be executed.

To model choices, the builder uses the **`or()`** method. This creates a list of nodes where **exactly one** of them must be completed. This is perfect for situations where a goal can be achieved in multiple ways, such as opening a door by either flipping a lever or using a superboom. The solver can then evaluate both options and choose the most efficient one.

Finally, the **`optional()`** method is used for conditional dependencies. This creates a list of nodes that may or may not be required. This is useful for modeling shortcuts or alternative strategies. For example, a path to a secret might be faster if an optional lever is flipped first, but the secret is still obtainable without it. The solver can then decide if the time saved by taking the shortcut is worth the time spent on the optional action.

## Resolving Possibilities: The `dagId`

These `or` and `optional` connections mean that a single ActionDAG can represent thousands, or even millions, of possible valid routes. To manage this complexity, the system uses a `dagId`—a single integer that acts as a compact, **bit-masked representation of a specific path** through the graph.

The `ActionDAGNode` class contains methods that use bitwise arithmetic on the `dagId` to resolve all the choices in the graph. Different bits in the `dagId` determine which path to take at each `or` connection and which of the `optional` dependencies to include. By iterating through all possible `dagId` values, the **[TSP Solver](./tsp-solver.md)** can effectively evaluate every single unique, valid path through the graph to find the one with the lowest total cost. This elegant solution allows the mod to model incredibly complex, non-linear tasks and then systematically find the single most efficient solution.
25 changes: 25 additions & 0 deletions docs/developer/core-systems/coordinates-and-room-detection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
sidebar_position: 2
---

# Coordinates and Room Detection

Before the mod can solve puzzles or find secrets, it must first solve two fundamental problems: where things are located within a room, and what room it's currently in. Dungeons Guide uses a clever combination of a relative coordinate system and a unique room "fingerprinting" method to handle this with precision and efficiency.

## 1. The Relative Coordinate System (`OffsetPoint` & `OffsetVec3`)

A dungeon room can spawn at any location in the world and can be rotated in one of four directions. Hard-coding the absolute coordinates of every secret and lever would be impossible. To solve this, the mod uses a relative coordinate system based on the `OffsetPoint` and `OffsetVec3` classes.

The purpose of an `OffsetPoint` is to store a coordinate (`x`, `y`, `z`) that is **relative to the corner of a room's schematic**, assuming zero rotation. This allows developers to define the location of a mechanic (like a chest at `(5, 10, 15)`) in a way that is completely independent of where the room spawns or how it's rotated. This is a fundamental concept that allows all `DungeonRoomInfo` blueprints to be defined in a consistent, reusable way.

At runtime, the `OffsetPoint` class provides the crucial mathematical transformations (`toRotatedRelBlockPos`, `setPosInWorld`) to convert between these abstract, schematic-relative coordinates and the actual, absolute coordinates in the Minecraft world. When a feature needs to know the real-world location of a mechanic, it provides the `OffsetPoint` from the static `DungeonMechanicData` and the current room's rotation. The class then handles the complex matrix transformations to return the correct `BlockPos`, ensuring that waypoints and solvers always have accurate information.

## 2. Room Detection and the `shape` Bitmask

When a player enters a new, unexplored area of the dungeon, the mod needs to identify what room it is so it can load the correct `DungeonRoomInfo` blueprint. This is accomplished through a room "fingerprinting" process managed by the `DungeonRoomScaffoldParser`.

When a new, unidentified room appears on the dungeon map, the `buildRoom` method is called. It performs a **flood-fill** algorithm on the map data, starting from a single point and expanding outwards to find all the connected "unit points" (the 16x16 segments on the map) that constitute a single, contiguous room.

Once the algorithm has the complete set of points belonging to the room, it generates a unique fingerprint for the room's footprint: the `shape` ID. It does this by normalizing the set of points to a 4x4 grid and then constructing a `short` (a 16-bit integer). The formula `shape |= 1 << (localY * 4 + localX)` sets a specific bit for each cell in the 4x4 grid that is part of the room. This creates a compact and unique bitmask that represents the exact shape of the room's footprint. For example, a simple 1x1 room would have a `shape` of `1` (binary `...0001`), while a 2x2 room in the top-left corner would have a shape of `51` (binary `...00110011`).

This unique `shape` ID, along with the room's color on the map, is then passed to the `RoomMatcher`. The `RoomMatcher` compares this fingerprint against its library of known `DungeonRoomInfo` blueprints to find the one that has the same shape and color, allowing it to definitively identify the room. Once a match is found, the system knows the room's rotation and can load all of its mechanics and pre-calculated data, enabling all of the mod's advanced features.
29 changes: 29 additions & 0 deletions docs/developer/core-systems/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
sidebar_position: 1
---

# Core Data Model: Blueprints and Instances

To understand how Dungeons Guide works, it is essential to grasp its core data model. The system is built on a clear and powerful separation between **static, pre-defined blueprints** and **dynamic, runtime instances**. This architecture allows the mod to use a rich, pre-calculated set of data for every known room in the game, while still being able to track the unique, changing state of every individual dungeon run.

## The Static Blueprints: `Info` & `Data`

The static half of the data model represents the unchanging, "textbook" definition of a dungeon room and all of its components. These objects are loaded from the mod's asset files (`.roomdata.cbor`) once when the game starts and are never modified during gameplay.

A `DungeonRoomInfo` object serves as the master blueprint for a specific dungeon room, such as the "1x1 Crusher Room". It contains all the static information about that room, including its physical schematic (the block data), its shape and color as they appear on the map, and a map of all its interactive elements.

This map of interactive elements is the key to the blueprint system. It contains `DungeonMechanicData` objects, which are the blueprints for individual mechanics like secrets, levers, or traps. A `DungeonSecretChestData` object, for example, knows the static location of a secret chest within the room's schematic. It defines *what* the mechanic is and its inherent properties, but knows nothing about its current state in a live game. Think of these as the raw schematics and parts lists for a room; they know everything about how a room *should* be, but nothing about what's happening in it *right now*.

## The Runtime Instances: `Room` & `State`

The runtime half of the data model represents the live, dynamic state of a room during an active dungeon run. These objects are created when a player enters a room and are destroyed when the run ends, holding all the information specific to that single instance of the room.

The `DungeonRoom` class is the runtime instance of a room. When the `DungeonRoomScaffoldParser` detects that the player has entered a new area, it creates a `DungeonRoom` object. This object holds a reference back to its `DungeonRoomInfo` blueprint, giving it access to all the static data. Most importantly, it manages a collection of `DungeonMechanicState` objects.

The `DungeonMechanicState` is the dynamic counterpart to `DungeonMechanicData` and the heart of the runtime state tracking. A new `DungeonMechanicState` object is instantiated for every mechanic in the room's blueprint when the `DungeonRoom` is created. This object holds the *current, mutable state* of that specific mechanic for the current run. For example, a `DungeonLeverState` object would have a property like `isFlipped`, which starts as `false` and is updated to `true` only when the player interacts with that specific lever in that specific run.

## The `RoomProcessor`: The Logic Engine

The `RoomProcessor` is the bridge that connects the static world of blueprints to the dynamic world of the live dungeon. When a `DungeonRoom` is created, it uses a `ProcessorFactory` to instantiate the correct type of `RoomProcessor` based on an ID string from the `DungeonRoomInfo` blueprint. This allows for specialized logic for different room types, such as a `RoomProcessorWaterPuzzle` or a `RoomProcessorBlazeSolver`.

The `RoomProcessor` acts as the "brain" of the room. It observes game events like chat messages, block updates, and entity deaths. It then interprets these events within the context of the room and updates the state of the `DungeonRoom` and its collection of `DungeonMechanicState` objects accordingly. This clean separation of data (the `State` objects) and logic (the `Processor`) is fundamental to the mod's ability to manage the complexity of Hypixel Dungeons.
Loading
Loading