Pathetic is a high-performance, backwards-compatible, and asynchronous pathfinding library designed for Spigot, Paper, and their forks. Pathetic leverages the A* algorithm with customizable heuristics for real-time pathfinding in Minecraft server environments.
Pathetic excels in handling complex terrains with features such as diagonal movement, vertical pathing, and user-defined filters for greater flexibility.
- Advanced A* Algorithm: Employs multiple distance metrics (Manhattan, Octile, Perpendicular) and height differences for pathfinding, optimized for 3D worlds like Minecraft.
- Asynchronous Pathfinding: Non-blocking operations using
CompletableFuture
to minimize server impact during pathfinding. - Fibonacci Heap for Efficient Queuing: The open set (frontier) is managed using a Fibonacci heap, ensuring
optimal node retrieval with faster
insert
andextract min
operations. - Customizable Heuristics: Fine-tune pathfinding behavior using
HeuristicWeights
for balanced navigation in any world configuration. - Regional Grid Optimization: Uses
ExpiringHashMap
and Bloom filters to efficiently track explored regions, minimizing memory overhead. - Dynamic Path Filters: Define custom filters to modify node validity or prioritize paths based on criteria such as passability, block type, or world boundaries.
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.patheloper.pathetic</groupId>
<artifactId>pathetic-mapping</artifactId>
<version>VERSION</version>
</dependency>
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.patheloper.pathetic:pathetic-mapping:VERSION'
}
Here’s how to set up and use Pathetic to find paths between random points in a Minecraft world:
public class AdvancedPathExample extends JavaPlugin {
@Override
public void onEnable() {
PatheticMapper.initialize(this);
findOptimizedPath(randomLocation(), randomLocation());
}
@Override
public void onDisable() {
PatheticMapper.shutdown();
}
private void findOptimizedPath(PathPosition start, PathPosition end) {
Pathfinder pathfinder = PatheticMapper.newPathfinder();
List<PathFilter> filters = List.of(new PassablePathFilter(), new CustomHeightFilter());
List<PathFilterStage> filterStages = List.of(new EarlyExitFilterStage());
pathfinder
.findPath(start, end, filters, filterStages)
.thenAccept(
pathfinderResult -> {
if (pathfinderResult.getPathState() == PathState.FOUND) {
pathfinderResult
.getPath()
.forEach(
location ->
player.sendBlockChange(
location, Material.GOLD_BLOCK.createBlockData()));
} else {
getLogger().info("Pathfinding failed or exceeded limits.");
}
});
}
private PathPosition randomLocation() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return new PathPosition(random.nextInt(0, 100), random.nextInt(0, 100), random.nextInt(0, 100));
}
}
- Javadocs: View Javadocs
- API Documentation: Access our Docs
Pathetic is released under the GPL License.
We welcome contributions! Feel free to fork the repository and submit pull requests. For major changes, open an issue first to discuss what you’d like to change.
For help and support, join our community on the SpigotMC forum thread or Discord Server.
We'd like to thank JetBrains for sponsoring the development of this project with an amazing toolset!