API Getting Started
Public Contract
Section titled “Public Contract”The API is in dev.despical.mazeengine.api and its model, request, operation, and event subpackages. It exposes three services:
| Service | Provides |
|---|---|
MazeRegistry | Saved maze snapshots, lookup by bounds, teleport coordinates, and graph routes |
PresetRegistry | Metadata for currently loaded presets |
MazeOperations | Accepted creation, regeneration, repair, and deletion requests |
Compile your integration against the public API without shading Maze Engine’s classes into your plugin. The project build produces separate API binaries and sources; API Javadocs can be generated with ./gradlew apiJavadoc. Use the GitHub source as the contract reference.
If Maze Engine is required, declare depend: [MazeEngine] in your Bukkit plugin.yml. For optional integration, use softdepend: [MazeEngine], verify provider availability, and keep code referencing its types within your optional integration path.
Load the Service
Section titled “Load the Service”Maze Engine registers MazeEngineApi with Bukkit’s ServicesManager while enabled. Resolve it after dependency enablement:
import dev.despical.mazeengine.api.MazeEngineApi;import org.bukkit.Bukkit;
MazeEngineApi api = Bukkit.getServicesManager().load(MazeEngineApi.class);if (api == null) { // MazeEngine is absent, disabled, or could not finish startup. return;}MazeEngineApi.VERSION is the public contract version, currently 1. It is independent of the plugin release version.
Thread and Lifetime Rules
Section titled “Thread and Lifetime Rules”Call registry queries, operation submission, progress sampling, and cancellation on the server thread while Maze Engine is enabled. Off-thread queries or use of a disabled provider throw IllegalStateException.
Returned lists, snapshots, routes, and completed results are immutable values. They can be retained without keeping a live Bukkit world reference and do not update themselves. Query again when your integration needs current record or preset state.
A completion is published on the server thread, but a callback attached after completion may execute on its attaching thread. Async callbacks use their selected executor. Schedule Bukkit work explicitly when necessary and never block the server thread with join() or get().
Do not retain a provider indefinitely across Maze Engine disable and enable cycles. Resolve the registered service again for a newly enabled lifecycle.
Look Up a Maze
Section titled “Look Up a Maze”import dev.despical.mazeengine.api.model.MazeId;import dev.despical.mazeengine.api.model.MazeSnapshot;
MazeId id = new MazeId("garden");api.mazes().find(id).ifPresent(maze -> { String theme = maze.preset().displayName(); int cellCount = maze.cells().count(); boolean ready = maze.status() == MazeSnapshot.Status.READY; // Update your menu or retain these immutable values.});MazeId normalizes names to lowercase and validates 1–48 letters, digits, underscores, or hyphens. It rejects reserved filesystem device names and does not trim surrounding whitespace.
all() includes preparing, generating, deleting, and failed records. A newly accepted create request still planning topology may be absent because it has no saved record yet. Use its operation handle to track that request.
Find the Current Volume
Section titled “Find the Current Volume”import dev.despical.mazeengine.api.model.MazeLocation;
var location = player.getLocation();var position = new MazeLocation( player.getWorld().getUID(), location.getBlockX(), location.getBlockY(), location.getBlockZ());var current = api.mazes().at(position);The query checks world UUID and all three coordinates against inclusive saved bounds. A position above the roof or below the floor is outside. The returned optional can include a busy or failed record.
Preset Metadata
Section titled “Preset Metadata”var themes = api.presets().all();var hedge = api.presets().find("hedge");Preset identifiers are case-insensitive. The current default is listed first, followed by display-name order. PresetSnapshot describes ID, display name, description, accent, difficulty, geometry, roof, requested snapshot, algorithm, and complexity.
Current preset queries reflect successful reloads. maze.preset() instead describes that saved maze’s frozen metadata. The API does not expose mutable palette or internal configuration objects.
Resolve Destinations
Section titled “Resolve Destinations”var entrance = api.mazes().entrance(new MazeId("garden"));var destination = api.mazes().destination(new MazeId("garden"));entrance resolves the centered arrival point at the entrance corridor, one block above the floor and facing inward. destination uses the saved custom point when present, otherwise the entrance. A custom point can belong to another world.
These calls resolve coordinates only. They require the selected world to be loaded, do not teleport a player, and do not validate the current arrival terrain. A snapshot’s optional custom destination is not the same as the resolved fallback destination.
Query a Route
Section titled “Query a Route”var maze = api.mazes().find(new MazeId("garden")).orElseThrow();var route = api.mazes().route(maze.id(), maze.entrance(), maze.exit());int steps = route.size() - 1;Route coordinates are zero-based logical cells, not world blocks. Routes include both endpoints, and identical endpoints produce one cell. A cell outside the grid is rejected.
The search follows saved topology and runs on the calling server thread with cost proportional to cell count. Retain the result for repeated display rather than querying on every animation tick. Live terrain edits do not automatically change the saved route.
Continue with operations and events to create or manage mazes and observe final results.