using System; using System.Collections.Generic; using MinecraftClient.Mapping; using MinecraftClient.Physics; namespace MinecraftClient.Pathing.Execution { public enum PathExecutorState { InProgress, Failed, Complete } /// /// Drives a sequence of PathSegments by instantiating the correct IActionTemplate /// for each segment and ticking it every game tick. /// public sealed class PathExecutor { private readonly List _segments; private int _currentIndex; private IActionTemplate? _currentTemplate; private readonly Action? _debugLog; public bool IsComplete => _currentIndex >= _segments.Count && _currentTemplate is null; public int CurrentIndex => _currentIndex; public int TotalSegments => _segments.Count; public PathSegment? CurrentSegment => _currentIndex < _segments.Count ? _segments[_currentIndex] : null; public PathExecutor(List segments, Action? debugLog = null) { _segments = segments; _currentIndex = 0; _debugLog = debugLog; AdvanceToNextSegment(); } public PathExecutorState Tick(Location pos, PlayerPhysics physics, MovementInput input, World world) { if (_currentTemplate is null) { input.Reset(); return PathExecutorState.Complete; } var state = _currentTemplate.Tick(pos, physics, input, world); switch (state) { case TemplateState.Complete: input.Reset(); _debugLog?.Invoke($"[PathExec] Segment {_currentIndex} complete " + $"({_segments[_currentIndex].MoveType}) at ({pos.X:F2},{pos.Y:F2},{pos.Z:F2})"); _currentIndex++; if (_currentIndex >= _segments.Count) { _currentTemplate = null; _debugLog?.Invoke("[PathExec] All segments complete!"); return PathExecutorState.Complete; } AdvanceToNextSegment(); return PathExecutorState.InProgress; case TemplateState.Failed: input.Reset(); _debugLog?.Invoke($"[PathExec] Segment {_currentIndex} FAILED " + $"({_segments[_currentIndex].MoveType}) at ({pos.X:F2},{pos.Y:F2},{pos.Z:F2}), " + $"target was ({_currentTemplate.ExpectedEnd.X:F2},{_currentTemplate.ExpectedEnd.Y:F2},{_currentTemplate.ExpectedEnd.Z:F2})"); return PathExecutorState.Failed; default: return PathExecutorState.InProgress; } } private void AdvanceToNextSegment() { if (_currentIndex < _segments.Count) { var seg = _segments[_currentIndex]; PathSegment? next = _currentIndex + 1 < _segments.Count ? _segments[_currentIndex + 1] : null; _currentTemplate = ActionTemplateFactory.Create(seg, next); _debugLog?.Invoke($"[PathExec] Starting segment {_currentIndex}/{_segments.Count}: {seg}"); } else { _currentTemplate = null; } } } }