Releases: labelle-toolkit/labelle-pathfinding
v2.7.0 - Hook System for Pathfinding Lifecycle Events
What's New
Hook System
A comptime-based, zero-overhead hook system for observing pathfinding lifecycle events.
Algorithm Hooks (A*, Floyd-Warshall):
path_requested- When pathfinding is initiatedpath_found- When a valid path is discoveredno_path_found- When no path exists between nodesnode_visited- When a node is visited during search (for debugging/visualization)search_complete- When the search algorithm finishes
Stair/Movement Hooks (PathfindingEngine):
stair_enter- When an entity enters a stairstair_exit- When an entity exits a stairstair_wait- When an entity starts waiting for a stair (blocked by traffic)
Usage Example
const MyHooks = struct {
pub fn path_found(payload: pathfinding.hooks.HookPayload) void {
const info = payload.path_found;
std.log.info("Path found! Cost: {d}", .{info.cost});
}
};
const Dispatcher = pathfinding.hooks.HookDispatcher(MyHooks);
var astar = pathfinding.AStarWithHooks(Dispatcher).init(allocator);Other Changes
MergePathfindingHooksfor combining multiple hook handlersEmptyDispatcheras default when no hooks are needed- Hooks emit entity IDs (not internal indices) when using mapping methods
v2.6.0 - Module rename and ECS Components export
Breaking Changes
-
Module renamed:
pathfinding→labelle_pathfindingUpdate your imports from:
const pathfinding = @import("pathfinding");
to:
const pathfinding = @import("labelle_pathfinding");
New Features
- Components export for ECS integration (#33): Export
Componentsstruct containingVec2,NodeId, andNodePointtypes for use with labelle-engine'sComponentRegistryMulti - labelle-engine integration example: New example demonstrating how to use pathfinding components in ECS entity definitions
Bug Fixes
- Module name mismatch (#35): The labelle CLI expects modules with underscored names matching the package name. Module is now correctly named
labelle_pathfinding.
🤖 Generated with Claude Code
v2.5.0 - Convenience functions, grid helper, and simplified config
What's New
Simplified Configuration
PathfindingEngineSimple(Entity, Context)- Quick setup without full Config struct
Grid Helper
createGrid(config)- Create grid of nodes with automatic connections in one call- Returns a
Gridstruct with coordinate utilities:toScreen,toNodeId,fromNodeId,nodePosition
Convenience Functions
connectAsGrid4(cell_size)- 4-directional movement (up/down/left/right)connectAsGrid8(cell_size)- 8-directional movement (including diagonals)
Vec2 Integration
- Position queries (
getPosition,getNodePosition) returnVec2from zig-utils - New methods:
addNodeVec2,registerEntityVec2
Full Changelog
v2.4.0
What's Changed
- Removed zig-ecs dependency - The library no longer depends on zig-ecs. The
PathfindingEngineis fully self-contained and manages entity positions directly. - Removed legacy ECS components (
MovementNode,ClosestMovementNode,MovingTowards,WithPath) - Removed
MovementNodeController
This is a breaking change if you were using the ECS integration. Migrate to using PathfindingEngine directly.
Full Changelog
v2.3.0 - Optimized Floyd-Warshall
What's New
Optimized Floyd-Warshall Implementations
This release adds high-performance Floyd-Warshall variants with significant speedups:
- FloydWarshallSimd - SIMD vectorization with flat memory layout (5-8x faster)
- FloydWarshallParallel - Multi-threaded + SIMD (up to 16x faster for large graphs)
Usage
Direct usage:
// SIMD-only (single-threaded)
var fw = pathfinding.FloydWarshallSimd.init(allocator);
// Parallel + SIMD (multi-threaded, best for 256+ nodes)
var fw = pathfinding.FloydWarshallParallel.init(allocator);With PathfindingEngine:
const Config = struct {
pub const Entity = u64;
pub const Context = *Game;
pub const floyd_warshall_variant: pathfinding.FloydWarshallVariant = .optimized_parallel;
};Benchmark
Run zig build run-benchmark to compare performance on your hardware.
Typical results (varies by CPU):
| Graph Size | Legacy | SIMD | Parallel |
|---|---|---|---|
| 128 nodes | 1.5ms | 0.2ms (8x) | 0.3ms (5x) |
| 256 nodes | 12ms | 2ms (6x) | 1ms (11x) |
| 512 nodes | 100ms | 15ms (7x) | 6ms (16x) |
Full Changelog
v2.2.1
Bug Fixes
Fix stair enter() called every frame (#19)
When an entity traversed a .single mode stair, state.enter() was called every frame, incrementing users_count repeatedly. On the second frame, canEnter() returned false, causing the entity to teleport to a waiting spot.
Fixed by:
- Check if entity is already using the stair before calling
enter() - Exit previous stair before entering a new one (multi-floor stairwells)
- Release stair state on
cancelPath()andunregisterEntity()
Improvements
- Extract
releaseStairState()helper to reduce code duplication - Add entity ID to debug log messages for better traceability
- Stricter test assertions for
users_count
v2.2.0
What's New
Log Level Configuration
Configure logging verbosity via the Config struct:
const Config = struct {
pub const Entity = u64;
pub const Context = *Game;
pub const log_level: pathfinding.LogLevel = .info; // defaults to .none
};Available levels: .none, .err, .warning, .info, .debug
Building Example
New run-building example demonstrating multi-floor pathfinding with stairs:
- Two-floor building layout
- Entities traversing between floors via stair nodes
- Uses building connection mode
Changes
- Add
LogLevelenum and comptime configuration - Add scoped logging helpers (
logErr,logWarn,logInfo,logDebug) - Add entity IDs to log messages for debugging
- Export
LogLevelfrom main pathfinding module - Add
usage/building_example.zig - Add
run-buildingbuild step
v2.1.0 - Stair Mode for Building Games
What's New
Stair Mode for Vertical Connections
This release adds support for 2D building games where vertical movement should only occur at designated stair nodes.
New Features
- Building Connection Mode - New
ConnectionMode.buildingthat creates horizontal connections normally but only creates vertical connections between nodes marked as stairs - StairMode Enum - Control traffic on stairs:
.none- Not a stair (default, no vertical connections).all- Multi-lane stair (unlimited concurrent usage).direction- Directional stair (multiple entities same direction only).single- Single-file stair (only one entity at a time)
- Waiting Areas - Define spots where entities wait when stairs are busy, preventing stacking
- Traffic Management - Runtime stair state tracking with queue-based access control
Example Usage
// Mark nodes as stairs
try engine.setStairMode(stair_bottom, .single);
try engine.setStairMode(stair_top, .single);
// Connect with building mode
try engine.connectNodes(.{
.building = .{ .horizontal_range = 60, .vertical_range = 120 },
});
// Optional: set waiting areas
try engine.setWaitingArea(stair_bottom, &waiting_spots);New API Methods
setStairMode(node, mode)- Set stair traffic modegetStairMode(node)- Get stair traffic modesetWaitingArea(node, spots)- Define waiting area for stairgetStairState(node)- Get runtime stair traffic state
Full Changelog
v2.0.0 - PathfindingEngine
What's New
This release introduces the PathfindingEngine, a self-contained pathfinding system that owns entity positions internally. This is now the recommended way to use the library.
New Features
-
PathfindingEngine - Complete solution with internal position management
- Comptime-configurable entity and context types
- Automatic graph building with
connectNodes() - Floyd-Warshall precomputed shortest paths
- Callbacks for path events (node reached, completed, blocked)
-
QuadTree - Spatial partitioning for O(log n) queries
getEntitiesInRadius()- Find entities within distancegetEntitiesInRect()- Find entities in rectanglegetNodesInRadius()- Find nearby waypoints
-
Connection Modes
- Omnidirectional: For top-down games (connect to N closest neighbors)
- Directional: For platformers (left/right/up/down connections)
Breaking Changes
PathfindingEngine.init()is now fallible (returns!Self)QuadTree.init(),reset(),resetWithBoundaries()are now fallible- Old examples replaced with new PathfindingEngine-focused examples
Migration
If you were using Floyd-Warshall or A* directly, they still work unchanged. For new projects, we recommend using PathfindingEngine instead.
const Config = struct {
pub const Entity = u64;
pub const Context = *Game;
};
var engine = try pathfinding.PathfindingEngine(Config).init(allocator);See the README for full documentation.
v1.0.3
Full Changelog: v1.0.2...v1.0.3