Skip to content

Commit

Permalink
Implement action direction system
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexProgrammerDE committed Jan 24, 2025
1 parent 385db1f commit d2a6906
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@

import com.google.common.math.DoubleMath;
import com.soulfiremc.server.pathfinding.execution.WorldAction;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import org.jetbrains.annotations.Nullable;

import java.util.List;

Expand All @@ -37,7 +39,12 @@ public final class MinecraftRouteNode implements Comparable<MinecraftRouteNode>
/**
* The currently best known node to this node.
*/
private MinecraftRouteNode parent;
private @Nullable MinecraftRouteNode parent;

/**
* The direction from the parent to this node.
*/
private @Nullable ActionDirection parentToNodeDirection;

/**
* The actions from the previous node to this node that were used to get to this node.
Expand Down Expand Up @@ -65,6 +72,7 @@ public MinecraftRouteNode(NodeState node, List<WorldAction> actions,
this(
node,
null,
null,
actions,
sourceCost,
targetCost,
Expand All @@ -82,10 +90,13 @@ public int compareTo(MinecraftRouteNode other) {
return DoubleMath.fuzzyCompare(this.targetCost, other.targetCost, 0.0001);
}

public void setBetterParent(MinecraftRouteNode parent, List<WorldAction> actions,
public void setBetterParent(MinecraftRouteNode parent,
ActionDirection moveDirection,
List<WorldAction> actions,
double sourceCost, double targetCost,
double totalRouteScore) {
this.parent = parent;
this.parentToNodeDirection = moveDirection;
this.actions = actions;
this.sourceCost = sourceCost;
this.targetCost = targetCost;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ public List<WorldAction> findRouteSync(NodeState from) {
}

try {
graph.insertActions(current.node(), instructions ->
handleInstructions(openSet, routeIndex, current, instructions));
graph.insertActions(
current.node(),
current.parentToNodeDirection(),
instructions -> handleInstructions(openSet, routeIndex, current, instructions)
);
} catch (OutOfLevelException e) {
log.debug("Found a node out of the level: {}", current.node());
stopwatch.stop();
Expand Down Expand Up @@ -210,6 +213,7 @@ private void handleInstructions(ObjectHeapPriorityQueue<MinecraftRouteNode> open
new MinecraftRouteNode(
instructionNode,
current,
instructions.moveDirection(),
worldActions,
newSourceCost,
newTargetCost,
Expand All @@ -226,6 +230,7 @@ private void handleInstructions(ObjectHeapPriorityQueue<MinecraftRouteNode> open
if (newSourceCost < v.sourceCost()) {
v.setBetterParent(
current,
instructions.moveDirection(),
worldActions,
newSourceCost,
newTargetCost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@

import com.soulfiremc.server.pathfinding.NodeState;
import com.soulfiremc.server.pathfinding.execution.WorldAction;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import lombok.With;

import java.util.List;

@With
public record GraphInstructions(
NodeState node, double actionCost, List<WorldAction> actions) {}
NodeState node, ActionDirection moveDirection, double actionCost, List<WorldAction> actions) {}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.soulfiremc.server.pathfinding.NodeState;
import com.soulfiremc.server.pathfinding.SFVec3i;
import com.soulfiremc.server.pathfinding.graph.actions.*;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import com.soulfiremc.server.protocol.bot.block.BlockAccessor;
import com.soulfiremc.server.protocol.bot.state.TagsState;
import com.soulfiremc.server.util.structs.LazyBoolean;
Expand Down Expand Up @@ -111,14 +112,19 @@ public boolean disallowedToBreakBlockType(BlockType blockType) {
return !pathConstraint.canBreakBlockType(blockType);
}

public void insertActions(NodeState node, Consumer<GraphInstructions> callback) {
public void insertActions(NodeState node, ActionDirection fromDirection, Consumer<GraphInstructions> callback) {
log.debug("Inserting actions for node: {}", node);
calculateActions(node, generateTemplateActions(), callback);
calculateActions(node, generateTemplateActions(fromDirection), callback);
}

private GraphAction[] generateTemplateActions() {
private GraphAction[] generateTemplateActions(ActionDirection fromDirection) {
var actions = new GraphAction[ACTIONS_TEMPLATE.length];
for (var i = 0; i < ACTIONS_TEMPLATE.length; i++) {
var action = ACTIONS_TEMPLATE[i];
if (fromDirection != null && action.actionDirection.opposite() == fromDirection) {
continue;
}

actions[i] = ACTIONS_TEMPLATE[i].copy();
}

Expand All @@ -135,7 +141,10 @@ private void calculateActions(
}

private void processSubscription(
NodeState node, GraphAction[] actions, Consumer<GraphInstructions> callback, int i) {
NodeState node,
GraphAction[] actions,
Consumer<GraphInstructions> callback,
int i) {
var key = SUBSCRIPTION_KEYS[i];
var value = SUBSCRIPTION_VALUES[i];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.soulfiremc.server.pathfinding.graph.BlockFace;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.pathfinding.graph.MinecraftGraph;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import com.soulfiremc.server.pathfinding.graph.actions.movement.BlockSafetyType;
import com.soulfiremc.server.pathfinding.graph.actions.movement.MovementMiningCost;
import com.soulfiremc.server.pathfinding.graph.actions.movement.SkyDirection;
Expand All @@ -46,6 +47,7 @@ public final class DownMovement extends GraphAction implements Cloneable {
private int closestObstructingBlock = Integer.MIN_VALUE;

private DownMovement(SubscriptionConsumer blockSubscribers) {
super(ActionDirection.DOWN);
this.targetToMineBlock = FEET_POSITION_RELATIVE_BLOCK.sub(0, 1, 0);

this.registerSafetyCheckBlocks(blockSubscribers);
Expand Down Expand Up @@ -112,6 +114,7 @@ public List<GraphInstructions> getInstructions(MinecraftGraph graph, NodeState n

return Collections.singletonList(new GraphInstructions(
new NodeState(absoluteTargetFeetBlock, node.usableBlockItems() + (breakCost.willDropUsableBlockItem() ? 1 : 0)),
actionDirection,
cost,
List.of(new BlockBreakAction(breakCost))));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.soulfiremc.server.pathfinding.NodeState;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.pathfinding.graph.MinecraftGraph;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

import java.util.List;
Expand All @@ -28,8 +30,10 @@
* A calculated action that the bot can take on a graph world representation.
*/
@Setter
@RequiredArgsConstructor
public abstract sealed class GraphAction
permits DownMovement, ParkourMovement, SimpleMovement, UpMovement {
public final ActionDirection actionDirection;
private int subscriptionCounter;

public boolean decrementAndIsDone() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.soulfiremc.server.pathfinding.execution.GapJumpAction;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.pathfinding.graph.MinecraftGraph;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import com.soulfiremc.server.util.SFBlockHelpers;
import com.soulfiremc.server.util.structs.LazyBoolean;
import lombok.Getter;
Expand All @@ -39,6 +40,7 @@ public final class ParkourMovement extends GraphAction implements Cloneable {
private final SFVec3i targetFeetBlock;

private ParkourMovement(ParkourDirection direction, SubscriptionConsumer blockSubscribers) {
super(direction.actionDirection);
this.direction = direction;
this.targetFeetBlock = direction.offset(direction.offset(FEET_POSITION_RELATIVE_BLOCK));

Expand Down Expand Up @@ -88,8 +90,10 @@ public List<GraphInstructions> getInstructions(MinecraftGraph graph, NodeState n

return Collections.singletonList(new GraphInstructions(
new NodeState(absoluteTargetFeetBlock, node.usableBlockItems()),
actionDirection,
Costs.ONE_GAP_JUMP,
List.of(new GapJumpAction(absoluteTargetFeetBlock))));
List.of(new GapJumpAction(absoluteTargetFeetBlock))
));
}

@Override
Expand Down Expand Up @@ -158,13 +162,14 @@ public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph
@Getter
@RequiredArgsConstructor
public enum ParkourDirection {
NORTH(new SFVec3i(0, 0, -1)),
SOUTH(new SFVec3i(0, 0, 1)),
EAST(new SFVec3i(1, 0, 0)),
WEST(new SFVec3i(-1, 0, 0));
NORTH(new SFVec3i(0, 0, -1), ActionDirection.NORTH),
SOUTH(new SFVec3i(0, 0, 1), ActionDirection.SOUTH),
EAST(new SFVec3i(1, 0, 0), ActionDirection.EAST),
WEST(new SFVec3i(-1, 0, 0), ActionDirection.WEST);

public static final ParkourDirection[] VALUES = values();
private final SFVec3i offsetVector;
private final ActionDirection actionDirection;

public SFVec3i offset(SFVec3i vector) {
return vector.add(offsetVector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public final class SimpleMovement extends GraphAction implements Cloneable {
private boolean requiresAgainstBlock = false;

private SimpleMovement(MovementDirection direction, MovementModifier modifier, SubscriptionConsumer blockSubscribers) {
super(modifier == MovementModifier.NORMAL ? direction.actionDirection() : ActionDirection.SPECIAL);
this.direction = direction;
this.modifier = modifier;
this.diagonal = direction.isDiagonal();
Expand Down Expand Up @@ -307,7 +308,11 @@ public List<GraphInstructions> getInstructions(MinecraftGraph graph, NodeState n
actions.add(new MovementAction(absoluteTargetFeetBlock, diagonal));

return Collections.singletonList(new GraphInstructions(
new NodeState(absoluteTargetFeetBlock, afterBreakUsableBlockItems), cost, actions));
new NodeState(absoluteTargetFeetBlock, afterBreakUsableBlockItems),
actionDirection,
cost,
actions
));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.soulfiremc.server.pathfinding.graph.BlockFace;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.pathfinding.graph.MinecraftGraph;
import com.soulfiremc.server.pathfinding.graph.actions.movement.ActionDirection;
import com.soulfiremc.server.pathfinding.graph.actions.movement.BlockSafetyType;
import com.soulfiremc.server.pathfinding.graph.actions.movement.MovementMiningCost;
import com.soulfiremc.server.pathfinding.graph.actions.movement.SkyDirection;
Expand All @@ -51,6 +52,7 @@ public final class UpMovement extends GraphAction implements Cloneable {
private boolean[] noNeedToBreak;

private UpMovement(SubscriptionConsumer blockSubscribers) {
super(ActionDirection.UP);
this.targetFeetBlock = FEET_POSITION_RELATIVE_BLOCK.add(0, 1, 0);

var arraySize = this.registerRequiredFreeBlocks(blockSubscribers);
Expand Down Expand Up @@ -134,7 +136,11 @@ public List<GraphInstructions> getInstructions(MinecraftGraph graph, NodeState n
node.blockPosition().sub(0, 1, 0), BlockFace.TOP)));

return Collections.singletonList(new GraphInstructions(
new NodeState(absoluteTargetFeetBlock, afterBreakUsableBlockItems), cost, actions));
new NodeState(absoluteTargetFeetBlock, afterBreakUsableBlockItems),
actionDirection,
cost,
actions
));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* SoulFire
* Copyright (C) 2024 AlexProgrammerDE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.soulfiremc.server.pathfinding.graph.actions.movement;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ActionDirection {
NORTH,
SOUTH,
EAST,
WEST,
NORTH_EAST,
NORTH_WEST,
SOUTH_EAST,
SOUTH_WEST,
UP,
DOWN,
// Jumps, diagonal jumps, falls, diagonal falls, etc.
// For those it's sometimes smart to fall down and then go in reverse direction, but lower/higher
SPECIAL;

public static final ActionDirection[] VALUES = values();

static {
NORTH.opposite = SOUTH;
SOUTH.opposite = NORTH;
EAST.opposite = WEST;
WEST.opposite = EAST;
NORTH_EAST.opposite = SOUTH_WEST;
NORTH_WEST.opposite = SOUTH_EAST;
SOUTH_EAST.opposite = NORTH_WEST;
SOUTH_WEST.opposite = NORTH_EAST;
UP.opposite = DOWN;
DOWN.opposite = UP;
SPECIAL.opposite = null;
}

private ActionDirection opposite;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@

@RequiredArgsConstructor
public enum MovementDirection {
NORTH(new SFVec3i(0, 0, -1), SkyDirection.NORTH, null),
SOUTH(new SFVec3i(0, 0, 1), SkyDirection.SOUTH, null),
EAST(new SFVec3i(1, 0, 0), SkyDirection.EAST, null),
WEST(new SFVec3i(-1, 0, 0), SkyDirection.WEST, null),
NORTH_EAST(new SFVec3i(1, 0, -1), null, DiagonalDirection.NORTH_EAST),
NORTH_WEST(new SFVec3i(-1, 0, -1), null, DiagonalDirection.NORTH_WEST),
SOUTH_EAST(new SFVec3i(1, 0, 1), null, DiagonalDirection.SOUTH_EAST),
SOUTH_WEST(new SFVec3i(-1, 0, 1), null, DiagonalDirection.SOUTH_WEST);
NORTH(new SFVec3i(0, 0, -1), SkyDirection.NORTH, null, ActionDirection.NORTH),
SOUTH(new SFVec3i(0, 0, 1), SkyDirection.SOUTH, null, ActionDirection.SOUTH),
EAST(new SFVec3i(1, 0, 0), SkyDirection.EAST, null, ActionDirection.EAST),
WEST(new SFVec3i(-1, 0, 0), SkyDirection.WEST, null, ActionDirection.WEST),
NORTH_EAST(new SFVec3i(1, 0, -1), null, DiagonalDirection.NORTH_EAST, ActionDirection.NORTH_EAST),
NORTH_WEST(new SFVec3i(-1, 0, -1), null, DiagonalDirection.NORTH_WEST, ActionDirection.NORTH_WEST),
SOUTH_EAST(new SFVec3i(1, 0, 1), null, DiagonalDirection.SOUTH_EAST, ActionDirection.SOUTH_EAST),
SOUTH_WEST(new SFVec3i(-1, 0, 1), null, DiagonalDirection.SOUTH_WEST, ActionDirection.SOUTH_WEST);

public static final MovementDirection[] VALUES = values();

Expand All @@ -50,6 +50,8 @@ public enum MovementDirection {
private final SkyDirection skyDirection;
private final DiagonalDirection diagonalDirection;
@Getter
private final ActionDirection actionDirection;
@Getter
private MovementDirection opposite;

public SFVec3i offset(SFVec3i vector) {
Expand Down

0 comments on commit d2a6906

Please sign in to comment.