Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed strategy brainfuck and turned it into a more proper solution. #37

Merged
merged 1 commit into from
Oct 5, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.NonNull;
import org.patheloper.api.pathing.result.PathfinderResult;
import org.patheloper.api.pathing.strategy.PathfinderStrategy;
import org.patheloper.api.wrapper.PathPosition;

import java.util.concurrent.CompletionStage;
Expand All @@ -12,10 +13,24 @@
public interface Pathfinder {

/**
* Tries to find a Path between the two {@link PathPosition}'s provided.
* Tries to find a Path between the two {@link PathPosition}'s provided directly.
*
* @see org.patheloper.api.pathing.strategy.strategies.DirectPathfinderStrategy
*
* @return An {@link CompletionStage} that will contain a {@link PathfinderResult}.
*
* @deprecated Use {@link #findPath(PathPosition, PathPosition, PathfinderStrategy)} instead.
*/
@NonNull
@Deprecated
CompletionStage<PathfinderResult> findPath(@NonNull PathPosition start, @NonNull PathPosition target);

/**
* Tries to find a Path between the two {@link PathPosition}'s provided with the given strategy.
*
* @param strategy The {@link PathfinderStrategy} to use
* @return An {@link CompletionStage} that will contain a {@link PathfinderResult}.
*/
@NonNull
CompletionStage<PathfinderResult> findPath(@NonNull PathPosition start, @NonNull PathPosition target, @NonNull PathfinderStrategy strategy);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.With;
import org.patheloper.api.pathing.strategy.strategies.DirectPathfinderStrategy;
import org.patheloper.api.pathing.strategy.PathfinderStrategy;

/**
* Configuration options for pathfinding.
*
* This class defines a set of rules that guide the behavior of the pathfinding process.
*
* - `strategy`: The class of the strategy to use for pathfinding. Defaults to {@link DirectPathfinderStrategy}.
*
* - `maxIterations`: The maximum number of iterations allowed during pathfinding. Set this to prevent infinite loops.
*
* - `maxLength`: The maximum length of the path. Avoid setting this too high as it can cause performance issues.
Expand Down Expand Up @@ -43,8 +39,6 @@
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class PathingRuleSet {

private static final Class<? extends PathfinderStrategy> DEFAULT_STRATEGY = DirectPathfinderStrategy.class;

/**
* @return A new {@link PathingRuleSet} with default values but async.
*/
Expand All @@ -59,8 +53,6 @@ public static PathingRuleSet createRuleSet() {
return builder().build();
}

@Builder.Default
Class<? extends PathfinderStrategy> strategy = DEFAULT_STRATEGY;
@Builder.Default
int maxIterations = 5000; // to avoid freewheeling
int maxLength;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public void onEnable() {

// Then you can use the PatheticMapper to get your own Pathfinder instance with your own set rules.
Pathfinder reusablePathfinder = PatheticMapper.newPathfinder(PathingRuleSet.createAsyncRuleSet()
.withStrategy(DirectPathfinderStrategy.class)
.withAllowingDiagonal(true)
.withAllowingFailFast(true)
.withAllowingFallback(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.bukkit.entity.Player;
import org.patheloper.api.pathing.Pathfinder;
import org.patheloper.api.pathing.result.PathfinderResult;
import org.patheloper.api.pathing.strategy.strategies.WalkablePathfinderStrategy;
import org.patheloper.api.wrapper.PathPosition;
import org.patheloper.mapping.bukkit.BukkitMapper;

Expand Down Expand Up @@ -66,7 +67,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
PathPosition target = BukkitMapper.toPathPosition(playerSession.getPos2());

player.sendMessage("Starting pathfinding...");
CompletionStage<PathfinderResult> pathfindingResult = pathfinder.findPath(start, target); // This is the actual pathfinding.
CompletionStage<PathfinderResult> pathfindingResult =
pathfinder.findPath(start, target, new WalkablePathfinderStrategy()); // This is the actual pathfinding.

// This is just a simple way to display the pathfinding result.
pathfindingResult.thenAccept(result -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public AStarPathfinder(PathingRuleSet pathingRuleSet) {
}

@Override
protected PathfinderResult findPath(PathPosition start, PathPosition target, PathfinderStrategy strategy) {
protected PathfinderResult resolvePath(PathPosition start, PathPosition target, PathfinderStrategy strategy) {
Node startNode = new Node(start.floor(), start.floor(), target.floor(), 0);

PriorityQueue<Node> nodeQueue = new PriorityQueue<>(Collections.singleton(startNode));
Expand Down Expand Up @@ -114,7 +114,7 @@ private Optional<PathfinderResult> fallback(Node fallbackNode) {

private Optional<PathfinderResult> counterCheck(PathPosition start, PathPosition target, PathfinderStrategy strategy) {
AStarPathfinder aStarPathfinder = new AStarPathfinder(pathingRuleSet.withCounterCheck(false));
PathfinderResult pathfinderResult = aStarPathfinder.findPath(target, start, strategy);
PathfinderResult pathfinderResult = aStarPathfinder.resolvePath(target, start, strategy);

if(pathfinderResult.getPathState() == PathState.FOUND)
return Optional.of(pathfinderResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.patheloper.api.pathing.result.PathfinderResult;
import org.patheloper.api.pathing.rules.PathingRuleSet;
import org.patheloper.api.pathing.strategy.PathfinderStrategy;
import org.patheloper.api.pathing.strategy.strategies.DirectPathfinderStrategy;
import org.patheloper.api.snapshot.SnapshotManager;
import org.patheloper.api.wrapper.PathBlock;
import org.patheloper.api.wrapper.PathPosition;
Expand All @@ -21,7 +22,6 @@
import org.patheloper.util.ErrorLogger;
import org.patheloper.util.NodeUtil;

import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
Expand All @@ -37,6 +37,8 @@ abstract class AbstractPathfinder implements Pathfinder {
protected static final Set<PathPosition> EMPTY_LINKED_HASHSET =
Collections.unmodifiableSet(new LinkedHashSet<>(0));

private static final PathfinderStrategy DEFAULT_STRATEGY = new DirectPathfinderStrategy();

private static final SnapshotManager SIMPLE_SNAPSHOT_MANAGER = new FailingSnapshotManager();
private static final SnapshotManager LOADING_SNAPSHOT_MANAGER =
new FailingSnapshotManager.RequestingSnapshotManager();
Expand All @@ -56,6 +58,7 @@ abstract class AbstractPathfinder implements Pathfinder {
);

protected final PathingRuleSet pathingRuleSet;

protected final Offset offset;
protected final SnapshotManager snapshotManager;

Expand All @@ -69,17 +72,23 @@ protected AbstractPathfinder(PathingRuleSet pathingRuleSet) {
@Override
public @NonNull CompletionStage<PathfinderResult> findPath(@NonNull PathPosition start,
@NonNull PathPosition target) {
PathfinderStrategy strategy = instantiateStrategy();
return findPath(start, target, DEFAULT_STRATEGY);
}

@Override
public @NonNull CompletionStage<PathfinderResult> findPath(@NonNull PathPosition start,
@NonNull PathPosition target,
@NonNull PathfinderStrategy strategy) {
PathingStartFindEvent startEvent = raiseStart(start, target, strategy);

if(initialChecksFailed(start, target, startEvent))
return CompletableFuture.completedFuture(finishPathing(new PathfinderResultImpl(
PathState.FAILED,
new PathImpl(start, target, EMPTY_LINKED_HASHSET))));

return producePathing(start, target, strategy);
}

protected PathfinderResult finishPathing(PathfinderResult pathfinderResult) {
EventPublisher.raiseEvent(new PathingFinishedEvent(pathfinderResult));
return pathfinderResult;
Expand Down Expand Up @@ -124,17 +133,6 @@ private boolean isBlockUnreachable(PathPosition position) {
return true;
}

private PathfinderStrategy instantiateStrategy() {
try {
return pathingRuleSet.getStrategy().getDeclaredConstructor().newInstance();
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
NoSuchMethodException e) {
throw ErrorLogger.logFatalError("Failed to instantiate PathfinderStrategy. Fell back to default");
}
}

private PathPosition relocateTargetPosition(PathPosition target) {
if (pathingRuleSet.isAllowingAlternateTarget() && isBlockUnreachable(target))
return NodeUtil.bubbleSearchAlternative(target, offset, snapshotManager).getPathPosition();
Expand All @@ -152,7 +150,7 @@ private CompletionStage<PathfinderResult> producePathing(PathPosition start, Pat
private CompletionStage<PathfinderResult> produceAsyncPathing(PathPosition start, PathPosition target, PathfinderStrategy strategy) {
return CompletableFuture.supplyAsync(() -> {
try {
return findPath(start, relocateTargetPosition(target), strategy);
return resolvePath(start, relocateTargetPosition(target), strategy);
} catch (Exception e) {
throw ErrorLogger.logFatalError("Failed to find path async");
}
Expand All @@ -161,11 +159,12 @@ private CompletionStage<PathfinderResult> produceAsyncPathing(PathPosition start

private CompletionStage<PathfinderResult> produceSyncPathing(PathPosition start, PathPosition target, PathfinderStrategy strategy) {
try {
return CompletableFuture.completedFuture(findPath(start, relocateTargetPosition(target), strategy));
return CompletableFuture.completedFuture(resolvePath(start, relocateTargetPosition(target), strategy));
} catch (Exception e) {
throw ErrorLogger.logFatalError("Failed to find path sync");
}
}

protected abstract PathfinderResult findPath(PathPosition start, PathPosition target, PathfinderStrategy strategy);

// name clash with the interface, therefore "resolve" instead of "find"
protected abstract PathfinderResult resolvePath(PathPosition start, PathPosition target, PathfinderStrategy strategy);
}