Skip to content
Open
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 @@ -20,6 +20,7 @@
import com.google.common.math.DoubleMath;
import com.soulfiremc.server.bot.BotConnection;
import com.soulfiremc.server.pathfinding.SFVec3i;
import com.soulfiremc.server.pathfinding.graph.constraint.PathConstraint;
import com.soulfiremc.server.util.MathHelper;
import com.soulfiremc.server.util.VectorHelper;
import lombok.RequiredArgsConstructor;
Expand All @@ -29,13 +30,18 @@
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;

import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@RequiredArgsConstructor
public final class MovementAction implements WorldAction {
private static final ThreadLocalRandom rand = ThreadLocalRandom.current();

private static final double STEP_HEIGHT = 0.6;
private final SFVec3i blockPosition;
// Corner jumps normally require you to stand closer to the block to jump
private final boolean walkFewTicksNoJump;
private final PathConstraint settings;
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field name settings is misleading here because the type is PathConstraint and it’s only used for movement constraints/jitter. Renaming it to something like pathConstraint (or constraint) would make the call sites and logic clearer.

Suggested change
private final PathConstraint settings;
private final PathConstraint pathConstraint;

Copilot uses AI. Check for mistakes.
private boolean didLook;
private boolean lockYRot;
private boolean wasStill;
Expand Down Expand Up @@ -88,7 +94,19 @@ public void tick(BotConnection connection) {

var previousYRot = clientEntity.getYRot();
clientEntity.lookAt(EntityAnchorArgument.Anchor.EYES, targetMiddleBlock);
clientEntity.setXRot(0);

var xRotation = 0f;
var yRotation = 0f;

if (settings.yawJitter().min() < settings.yawJitter().max()) {
yRotation = rand.nextFloat((float) settings.yawJitter().min(), (float) settings.yawJitter().max());
}
if (settings.pitchJitter().min() < settings.pitchJitter().max()) {
xRotation = rand.nextFloat((float) settings.pitchJitter().min(), (float) settings.pitchJitter().max());
}

clientEntity.setYRot(clientEntity.getYRot() + yRotation);
clientEntity.setXRot(xRotation);
var newYRot = clientEntity.getYRot();

var yRotDifference = Math.abs(MathHelper.wrapDegrees(newYRot - previousYRot));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ private PathExecutor(
this.pathCompletionFuture = pathCompletionFuture;
}

private static List<WorldAction> repositionIfNeeded(List<WorldAction> actions, SFVec3i from, boolean requiresRepositioning) {
private static List<WorldAction> repositionIfNeeded(List<WorldAction> actions, SFVec3i from, boolean requiresRepositioning, LiveRouteFinder findPath) {
if (!requiresRepositioning) {
return actions;
}

var repositionActions = new ArrayList<WorldAction>();
repositionActions.add(new MovementAction(from, false));
repositionActions.add(new MovementAction(from, false, findPath.pathConstraint));
repositionActions.addAll(actions);

return repositionActions;
Expand Down Expand Up @@ -118,7 +118,7 @@ public void submitForPathCalculation(boolean isInitial) {

SFHelpers.mustSupply(() -> switch (routeSearchResult.routeSearchResult()) {
case RouteFinder.FoundRouteResult foundRouteResult -> () -> {
var newActions = repositionIfNeeded(foundRouteResult.actions(), routeSearchResult.start(), isInitial);
var newActions = repositionIfNeeded(foundRouteResult.actions(), routeSearchResult.start(), isInitial, this.findPath);
if (newActions.isEmpty()) {
log.info("We're already at the goal!");
return;
Expand All @@ -133,7 +133,7 @@ public void submitForPathCalculation(boolean isInitial) {
};
case RouteFinder.NoRouteFoundResult _ -> throw new IllegalStateException("No route found to the goal!");
case RouteFinder.PartialRouteResult partialRouteResult -> () -> {
var newActions = addRecalculate(repositionIfNeeded(partialRouteResult.actions(), routeSearchResult.start(), isInitial));
var newActions = addRecalculate(repositionIfNeeded(partialRouteResult.actions(), routeSearchResult.start(), isInitial, this.findPath));
if (newActions.isEmpty()) {
log.info("We're already at the goal!");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ public List<GraphInstructions> getInstructions(MinecraftGraph graph, SFVec3i nod
actions.add(new BlockPlaceAction(floorBlock, blockPlaceAgainstData));
}

actions.add(new MovementAction(absoluteTargetFeetBlock, diagonal));
actions.add(new MovementAction(absoluteTargetFeetBlock, diagonal, graph.pathConstraint()));
if (interactablePassage != null) {
actions.add(new InteractBlockAction(interactablePassage.block(), interactablePassage.interactFace(), false));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.soulfiremc.server.pathfinding.SFVec3i;
import com.soulfiremc.server.pathfinding.graph.DiagonalCollisionCalculator;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.settings.property.MinMaxProperty;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;

Expand Down Expand Up @@ -99,5 +100,15 @@ default boolean disablePruning() {
return delegate().disablePruning();
}

@Override
default MinMaxProperty.DataLayout yawJitter() {
return delegate().yawJitter();
}

@Override
default MinMaxProperty.DataLayout pitchJitter() {
return delegate().pitchJitter();
}

PathConstraint delegate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.soulfiremc.server.pathfinding.SFVec3i;
import com.soulfiremc.server.pathfinding.graph.DiagonalCollisionCalculator;
import com.soulfiremc.server.pathfinding.graph.GraphInstructions;
import com.soulfiremc.server.settings.property.MinMaxProperty;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;

Expand Down Expand Up @@ -58,4 +59,8 @@ public interface PathConstraint {

/// Returns whether pruning of the pathfinding search space is disabled.
boolean disablePruning();

MinMaxProperty.DataLayout yawJitter();

MinMaxProperty.DataLayout pitchJitter();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.soulfiremc.server.settings.lib.BotSettingsSource;
import com.soulfiremc.server.settings.lib.InstanceSettingsSource;
import com.soulfiremc.server.settings.lib.SettingsSource;
import com.soulfiremc.server.settings.property.MinMaxProperty;
import com.soulfiremc.server.util.SFBlockHelpers;
import com.soulfiremc.server.util.SFItemHelpers;
import com.soulfiremc.server.util.structs.CachedLazyObject;
Expand Down Expand Up @@ -56,6 +57,8 @@ public final class PathConstraintImpl implements PathConstraint {
private final int placeBlockPenalty;
private final int expireTimeout;
private final boolean disablePruning;
private final MinMaxProperty.DataLayout yawJitter;
private final MinMaxProperty.DataLayout pitchJitter;
private final CachedLazyObject<List<EntityRangeData>> unfriendlyEntities = new CachedLazyObject<>(this::getUnfriendlyEntitiesExpensive, 10, TimeUnit.SECONDS);

public PathConstraintImpl(
Expand All @@ -68,7 +71,9 @@ public PathConstraintImpl(
int breakBlockPenalty,
int placeBlockPenalty,
int expireTimeout,
boolean disablePruning) {
boolean disablePruning,
MinMaxProperty.DataLayout yawJitter,
MinMaxProperty.DataLayout pitchJitter) {
this.entity = entity;
this.levelHeightAccessor = levelHeightAccessor;
this.allowBreakingUndiggable = allowBreakingUndiggable;
Expand All @@ -79,6 +84,8 @@ public PathConstraintImpl(
this.placeBlockPenalty = placeBlockPenalty;
this.expireTimeout = expireTimeout;
this.disablePruning = disablePruning;
this.yawJitter = yawJitter;
this.pitchJitter = yawJitter;
}

public PathConstraintImpl(BotConnection botConnection) {
Expand All @@ -103,7 +110,9 @@ public PathConstraintImpl(
settingsSource.get(PathfindingSettings.BREAK_BLOCK_PENALTY),
settingsSource.get(PathfindingSettings.PLACE_BLOCK_PENALTY),
settingsSource.get(PathfindingSettings.EXPIRE_TIMEOUT),
settingsSource.get(PathfindingSettings.DISABLE_PRUNING)
settingsSource.get(PathfindingSettings.DISABLE_PRUNING),
settingsSource.get(PathfindingSettings.YAW_JITTER),
settingsSource.get(PathfindingSettings.PITCH_JITTER)
);
}

Expand Down Expand Up @@ -213,6 +222,16 @@ public boolean disablePruning() {
return disablePruning;
}

@Override
public MinMaxProperty.DataLayout yawJitter() {
return yawJitter;
}

@Override
public MinMaxProperty.DataLayout pitchJitter() {
return pitchJitter;
}

private List<EntityRangeData> getUnfriendlyEntitiesExpensive() {
if (entity == null) {
return List.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@

import com.soulfiremc.server.settings.lib.SettingsObject;
import com.soulfiremc.server.settings.lib.SettingsSource;
import com.soulfiremc.server.settings.property.BooleanProperty;
import com.soulfiremc.server.settings.property.ImmutableBooleanProperty;
import com.soulfiremc.server.settings.property.ImmutableIntProperty;
import com.soulfiremc.server.settings.property.IntProperty;
import com.soulfiremc.server.settings.property.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

Expand Down Expand Up @@ -109,4 +106,40 @@ public final class PathfindingSettings implements SettingsObject {
.description("Disable periodic pruning of the pathfinding search space (may use more memory)")
.defaultValue(false)
.build();
public static final MinMaxProperty<SettingsSource.Bot> YAW_JITTER =
ImmutableMinMaxProperty.<SettingsSource.Bot>builder()
.sourceType(SettingsSource.Bot.INSTANCE)
.namespace(NAMESPACE)
.key("yaw-jitter")
.minValue(-180)
.maxValue(180)
.minEntry(ImmutableMinMaxPropertyEntry.builder()
.uiName("Yaw Jitter Minimum")
.description("Minimum random horizontal angle offset")
.defaultValue(-25)
.build())
.maxEntry(ImmutableMinMaxPropertyEntry.builder()
.uiName("Yaw Jitter Maximum")
.description("Maximum random horizontal angle offset")
.defaultValue(25)
.build())
.build();
public static final MinMaxProperty<SettingsSource.Bot> PITCH_JITTER =
ImmutableMinMaxProperty.<SettingsSource.Bot>builder()
.sourceType(SettingsSource.Bot.INSTANCE)
.namespace(NAMESPACE)
.key("pitch-jitter")
.minValue(-90)
.maxValue(90)
.minEntry(ImmutableMinMaxPropertyEntry.builder()
.uiName("Pitch Jitter Minimum")
.description("Minimum random vertical angle offset")
.defaultValue(-4)
.build())
.maxEntry(ImmutableMinMaxPropertyEntry.builder()
.uiName("Pitch Jitter Maximum")
.description("Maximum random vertical angle offset")
.defaultValue(4)
.build())
.build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.soulfiremc.server.pathfinding.graph.constraint.DelegatePathConstraint;
import com.soulfiremc.server.pathfinding.graph.constraint.PathConstraint;
import com.soulfiremc.server.pathfinding.graph.constraint.PathConstraintImpl;
import com.soulfiremc.server.settings.property.MinMaxProperty;
import org.jspecify.annotations.NonNull;

public final class TestPathConstraint implements DelegatePathConstraint {
Expand All @@ -35,7 +36,9 @@ public final class TestPathConstraint implements DelegatePathConstraint {
2, // breakBlockPenalty
5, // placeBlockPenalty
180, // expireTimeout
false // disablePruning
false, // disablePruning
new MinMaxProperty.DataLayout(-25, 25), // yawJitter
new MinMaxProperty.DataLayout(-4, 4) // pitchJitter
);

private TestPathConstraint() {}
Expand Down