Skip to content

Commit

Permalink
Merge pull request #62 from patheloper/trunk
Browse files Browse the repository at this point in the history
Many important changes for 2.4
  • Loading branch information
Metaphoriker authored Mar 10, 2024
2 parents 02dde01 + 1c2ae28 commit c63d140
Show file tree
Hide file tree
Showing 56 changed files with 877 additions and 243 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ name: Build Pathetic
on:
push:
branches:
- stage
- production
pull_request:
types:
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ public class PathExample extends JavaPlugin {

@Override
public void onEnable() {

PatheticMapper.initialize(this);
goFindSomePath(randomLocation(), randomLocation());
}

private void goFindSomePath(PathPosition start, PathPosition end) {
@Override
public void onDisable() {
PatheticMapper.shutdown();
}

private void goFindSomePath(PathPosition start, PathPosition end) {
Pathfinder pathfinder = PatheticMapper.newPathfinder();
pathfinder
.findPath(start, end, new DirectPathfinderStrategy())
Expand Down
4 changes: 2 additions & 2 deletions pathetic-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<parent>
<artifactId>pathetic-main</artifactId>
<groupId>org.patheloper</groupId>
<version>2.3</version>
<version>2.4</version>
</parent>

<artifactId>pathetic-api</artifactId>
<version>2.3</version>
<version>2.4</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.patheloper.api.pathing.configuration;

import lombok.Value;

/**
* Represents a set of weights used to calculate a heuristic for the A* pathfinding algorithm. These
* weights influence the prioritization of different path characteristics during the search.
*
* <p>This class defines weights for the following distance metrics:
*
* <ul>
* <li><b>Manhattan Distance:</b> Prioritizes direct movement along axes.
* <li><b>Octile Distance:</b> Allows for diagonal movement for finer-grained pathing.
* <li><b>Perpendicular Distance:</b> Penalizes deviation from the straight line to the target,
* aiding in smoother paths.
* <li><b>Height Difference:</b> Factors in elevation changes when calculating path costs.
* </ul>
*/
@Value(staticConstructor = "create")
public class HeuristicWeights {

/**
* Provides a set of default heuristic weights that may be suitable for natural pathfinding. These
* values can be adjusted for specific scenarios.
*/
public static final HeuristicWeights NATURAL_PATH_WEIGHTS = create(0.3, 0.15, 0.6, 0.3);

/**
* Provides a set of weights strongly prioritizing the shortest direct path, even if diagonally.
*/
public static final HeuristicWeights DIRECT_PATH_WEIGHTS = create(0.6, 0.3, 0.0, 0.1);

/**
* The weight applied to the Manhattan distance component of the heuristic. A higher weight
* favours paths with a greater emphasis on direct, axis-aligned movement.
*/
double manhattenWeight;

/**
* The weight applied to the Octile distance component of the heuristic. A higher weight allows
* diagonal movement, enabling more flexible paths in 3D environments.
*/
double octileWeight;

/**
* The weight applied to the perpendicular distance component of the heuristic. Increased weight
* discourages deviations from the straight line between the start and target, resulting in
* smoother paths.
*/
double perpendicularWeight;

/**
* The weight applied to the height difference (elevation change) component of the heuristic. A
* higher weight gives more consideration to vertical distance, important for terrains with
* varying verticality.
*/
double heightWeight;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.patheloper.api.pathing.configuration;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.With;

/**
* Defines a set of configurable rules that govern the behavior of the A* pathfinding algorithm. By
* adjusting these settings, you can fine-tune the pathfinding process to suit the specific needs of
* your Minecraft environment.
*/
@With
@Value
@Getter
@Builder(toBuilder = true, access = AccessLevel.PRIVATE)
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class PathingRuleSet {

/**
* The maximum number of iterations allowed for the pathfinding algorithm. This acts as a
* safeguard to prevent infinite loops in complex scenarios.
*
* @default 5000
*/
@Builder.Default int maxIterations = 5000;

/**
* The maximum permissible length of a calculated path (in blocks). Use this to constrain long
* searches that could impact performance. A value of 0 indicates no limit.
*/
int maxLength;

/**
* Determines whether pathfinding calculations should be executed asynchronously in a separate
* thread. This can improve responsiveness in the main thread, but may introduce synchronization
* complexities.
*/
boolean async;

/**
* Controls whether the pathfinding algorithm can take diagonal steps. Enabling this allows for
* more flexible and potentially shorter paths but might require a slightly more refined
* heuristic.
*
* @default true
*/
@Builder.Default boolean allowingDiagonal = true;

/**
* If set to true, the pathfinding process will terminate immediately if no path is found between
* the start and target. This can be helpful for quick validation but prevents fallback
* strategies.
*/
boolean allowingFailFast;

/**
* If pathfinding fails, this setting determines whether the algorithm should fall back to the
* last successfully calculated path. This can help maintain progress, but might use an outdated
* path.
*/
boolean allowingFallback;

/**
* Controls whether chunks should be loaded or generated as needed during the pathfinding process.
* This is essential for exploring uncharted areas, but may impact performance.
*/
boolean loadingChunks;

/**
* If pathfinding fails, determines whether to run a reverse pathfinding check (from target to
* start) to verify the result. This is a computationally expensive fallback but can help identify
* some failure cases.
*/
boolean counterCheck;

/**
* The set of weights used to calculate heuristics within the A* algorithm. These influence the
* pathfinding priority for distance, elevation changes, smoothness, and diagonal movement.
*
* @default HeuristicWeights.NATURAL_PATH_WEIGHTS
*/
@Builder.Default HeuristicWeights heuristicWeights = HeuristicWeights.NATURAL_PATH_WEIGHTS;

/**
* @return A new {@link PathingRuleSet} with default values but async.
*/
public static PathingRuleSet createAsyncRuleSet() {
return builder().async(true).build();
}

/**
* @return A new {@link PathingRuleSet} with default values.
*/
public static PathingRuleSet createRuleSet() {
return builder().build();
}

/**
* Creates a deep copy of the given {@link PathingRuleSet}.
*
* <p>This method constructs a new instance of {@link PathingRuleSet} with the same values as the
* input. It ensures a deep copy by copying the values of primitive and boolean fields directly.
*
* @param pathingRuleSet The {@link PathingRuleSet} to copy.
* @return A new {@link PathingRuleSet} instance with the same values as the input.
*/
public static PathingRuleSet deepCopy(PathingRuleSet pathingRuleSet) {
return builder()
.maxIterations(pathingRuleSet.maxIterations)
.maxLength(pathingRuleSet.maxLength)
.async(pathingRuleSet.async)
.allowingDiagonal(pathingRuleSet.allowingDiagonal)
.allowingFailFast(pathingRuleSet.allowingFailFast)
.allowingFallback(pathingRuleSet.allowingFallback)
.loadingChunks(pathingRuleSet.loadingChunks)
.counterCheck(pathingRuleSet.counterCheck)
.heuristicWeights(pathingRuleSet.heuristicWeights)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import org.patheloper.api.util.ParameterizedSupplier;
import org.patheloper.api.wrapper.PathPosition;

public interface Path {
import java.util.function.Consumer;

public interface Path extends Iterable<PathPosition> {

/**
* The length of the Path compiled from the number of positions
Expand Down Expand Up @@ -83,7 +85,11 @@ public interface Path {
@NonNull
PathPosition getEnd();

/** Returns the path from the Pathfinder as a {@link Iterable} full of {@link PathPosition} */
/**
* Returns the path from the Pathfinder as a {@link Iterable} full of {@link PathPosition}
* @deprecated Will be removed in future versions {@link #forEach(Consumer)}
*/
@NonNull
@Deprecated
Iterable<PathPosition> getPositions();
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.patheloper.api.pathing.strategy.strategies;

import org.bukkit.Material;
import org.patheloper.api.pathing.strategy.PathValidationContext;
import org.patheloper.api.pathing.strategy.PathfinderStrategy;
import org.patheloper.api.snapshot.SnapshotManager;
import org.patheloper.api.wrapper.PathPosition;

public class BoatStrategy implements PathfinderStrategy {

@Override
public boolean isValid(PathValidationContext pathValidationContext) {
SnapshotManager snapshotManager = pathValidationContext.getSnapshotManager();
PathPosition pathPosition = pathValidationContext.getPosition();

return snapshotManager
.getBlock(pathPosition.subtract(0, 1, 0))
.getBlockInformation()
.getMaterial()
== Material.WATER
&& snapshotManager.getBlock(pathPosition).isPassable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,21 @@ public boolean isValid(@NonNull PathValidationContext pathValidationContext) {
return true;
}

if ((position.getBlockY() - lastValidPosition.getBlockY()) > jumpHeight) return false;
int heightDiff = position.getBlockY() - lastValidPosition.getBlockY();
if (isJumpingDown(position, lastValidPosition)) {
heightDiff *= -1;
}

if (heightDiff > jumpHeight) {
return false;
}

return startBlock.isPassable() && position.distance(lastValidPosition) <= maxJumpDistance;
}

private boolean isJumpingDown(PathPosition position, PathPosition lastValidPosition) {
return position.getBlockX() == lastValidPosition.getBlockX()
&& position.getBlockZ() == lastValidPosition.getBlockZ()
&& position.getBlockY() < lastValidPosition.getBlockY();
}
}
Loading

0 comments on commit c63d140

Please sign in to comment.