mirror of
https://github.com/AutismDevelopment/Autism-Client.git
synced 2026-10-28 19:39:48 +00:00
Refactor: extract MacroBreak from MacroExecutor (upstream #4)
Move 26 insta-break/break-engine methods verbatim into MacroBreak. Shared members referenced as MacroExecutor.xxx (mechanical qualification only); dispatch call sites of runInstaBreakAction, runBreakAction and sendBlockInteract re-pointed. All bodies verified identical against HEAD modulo that qualification.
This commit is contained in:
parent
c78be74b37
commit
79c1e81cc6
2 changed files with 559 additions and 536 deletions
548
src/main/java/autismclient/util/macro/MacroBreak.java
Normal file
548
src/main/java/autismclient/util/macro/MacroBreak.java
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
package autismclient.util.macro;
|
||||
|
||||
import autismclient.mixin.accessor.AutismMultiPlayerGameModeAccessor;
|
||||
import autismclient.modules.AutismModule;
|
||||
import autismclient.util.AutismAutoTool;
|
||||
import autismclient.util.AutismClientMessaging;
|
||||
import autismclient.util.AutismInstaBreakRenderer;
|
||||
import autismclient.util.AutismInventoryHelper;
|
||||
import autismclient.util.AutismSharedState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
final class MacroBreak {
|
||||
private MacroBreak() {
|
||||
}
|
||||
public static void runInstaBreakAction(Minecraft mc, InstaBreakAction action) throws InterruptedException {
|
||||
if (mc == null || mc.player == null || mc.level == null || mc.getConnection() == null || mc.gameMode == null) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cInstaBreak: missing world or connection");
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos target = action.blockPos == null ? BlockPos.ZERO : action.blockPos;
|
||||
Direction direction = action.direction == null ? Direction.UP : action.direction;
|
||||
int delayTicks = Math.max(0, action.delayTicks);
|
||||
int targetTimes = Math.max(0, action.times);
|
||||
int completed = 0;
|
||||
boolean wasSolid = !isInstaBreakAir(mc, target);
|
||||
|
||||
if (!ensureInstaBreakPickaxe(mc, action)) return;
|
||||
|
||||
AutismInstaBreakRenderer.setTarget(target);
|
||||
try {
|
||||
long lastAttemptTick = AutismSharedState.get().getClientTickCounter() - (delayTicks + 1L);
|
||||
long lastSneakTick = Long.MIN_VALUE;
|
||||
while (MacroExecutor.isCurrentRunActive() && isActionStillInCurrentMacro(action)) {
|
||||
|
||||
if (action.sneak) {
|
||||
long sneakTick = AutismSharedState.get().getClientTickCounter();
|
||||
if (sneakTick != lastSneakTick) {
|
||||
lastSneakTick = sneakTick;
|
||||
final String sneakMode = action.sneakMode;
|
||||
MacroExecutor.runOnClientThread(mc, () -> holdMacroSneak(mc, sneakMode), action.isTickAligned());
|
||||
}
|
||||
}
|
||||
|
||||
boolean isAir = isInstaBreakAir(mc, target);
|
||||
if (wasSolid && isAir) {
|
||||
completed++;
|
||||
MacroExecutor.setCurrentStatus("InstaBreak " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
if (targetTimes > 0 && completed >= targetTimes) return;
|
||||
wasSolid = false;
|
||||
} else if (!isAir) {
|
||||
wasSolid = true;
|
||||
}
|
||||
|
||||
if (!isAir) {
|
||||
long currentTick = AutismSharedState.get().getClientTickCounter();
|
||||
if (currentTick != lastAttemptTick && (currentTick - lastAttemptTick) >= delayTicks) {
|
||||
lastAttemptTick = currentTick;
|
||||
if (!ensureInstaBreakPickaxe(mc, action)) return;
|
||||
if (action.interact) {
|
||||
|
||||
InteractTiming t = action.interactTiming;
|
||||
boolean interactFirst = t == InteractTiming.BEFORE || t == InteractTiming.WITH
|
||||
|| (t == InteractTiming.CUSTOM && action.interactCustomMs < 0);
|
||||
long ns = t == InteractTiming.CUSTOM
|
||||
? Math.abs((long) action.interactCustomMs) * 1_000_000L : 0L;
|
||||
if (interactFirst) {
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
} else if (t == InteractTiming.AFTER_PLUS) {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
MacroExecutor.waitOneTick();
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
} else {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
}
|
||||
} else {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MacroExecutor.setCurrentStatus("InstaBreak " + target.getX() + "," + target.getY() + "," + target.getZ()
|
||||
+ " " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} finally {
|
||||
if (action.sneak) {
|
||||
final String sneakMode = action.sneakMode;
|
||||
try {
|
||||
MacroExecutor.runOnClientThread(mc, () -> releaseMacroSneak(mc, sneakMode));
|
||||
} catch (InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
AutismInstaBreakRenderer.clearTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInstaBreakAir(Minecraft mc, BlockPos pos) {
|
||||
|
||||
return mc.level == null || mc.level.isOutsideBuildHeight(pos) || mc.level.getBlockState(pos).isAir();
|
||||
}
|
||||
|
||||
private static boolean isActionStillInCurrentMacro(MacroAction action) {
|
||||
MacroExecutor.RunState run = MacroExecutor.CURRENT_RUN.get();
|
||||
if (run == null || run.macro == null || run.macro.actions == null) return true;
|
||||
return run.macro.actions.contains(action);
|
||||
}
|
||||
|
||||
private static boolean ensureInstaBreakPickaxe(Minecraft mc, InstaBreakAction action) throws InterruptedException {
|
||||
|
||||
return MacroExecutor.callOnClientThread(mc, () -> {
|
||||
if (mc.player == null) return false;
|
||||
if (mc.player.getMainHandItem().is(ItemTags.PICKAXES)) return true;
|
||||
if (!action.autoPickaxe) return false;
|
||||
|
||||
int preferred = Math.max(0, Math.min(8, mc.player.getInventory().getSelectedSlot()));
|
||||
for (int slot = 0; slot < 9; slot++) {
|
||||
if (mc.player.getInventory().getItem(slot).is(ItemTags.PICKAXES)) {
|
||||
AutismInventoryHelper.selectHotbarSlot(mc, slot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int slot = 9; slot < 36; slot++) {
|
||||
if (mc.player.getInventory().getItem(slot).is(ItemTags.PICKAXES)) {
|
||||
if (!AutismInventoryHelper.swapInventorySlots(mc, slot, preferred)) return false;
|
||||
AutismInventoryHelper.selectHotbarSlot(mc, preferred);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, false, action.isTickAligned());
|
||||
}
|
||||
|
||||
private static void sendInstaBreakAttempt(Minecraft mc, BlockPos pos, Direction direction, boolean tickAligned) throws InterruptedException {
|
||||
MacroExecutor.runOnClientThread(mc, () -> {
|
||||
if (mc.player == null || mc.level == null || mc.gameMode == null || mc.getConnection() == null) return;
|
||||
BlockPos blockPos = pos.immutable();
|
||||
Direction dir = direction == null ? Direction.UP : direction;
|
||||
|
||||
if (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor accessor) {
|
||||
accessor.autism$startPrediction(mc.level, sequence -> new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, dir, sequence));
|
||||
accessor.autism$startPrediction(mc.level, sequence -> new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, blockPos, dir, sequence));
|
||||
} else {
|
||||
|
||||
mc.getConnection().send(new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, dir));
|
||||
mc.getConnection().send(new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, blockPos, dir));
|
||||
}
|
||||
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
}, tickAligned);
|
||||
}
|
||||
|
||||
public static void runBreakAction(Minecraft mc, BreakAction action) throws InterruptedException {
|
||||
if (mc == null || mc.player == null || mc.level == null || mc.getConnection() == null || mc.gameMode == null) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak: missing world or connection");
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockPos target = action.blockPos == null ? BlockPos.ZERO : action.blockPos;
|
||||
final Direction direction = action.direction == null ? Direction.UP : action.direction;
|
||||
int startDelay = Math.max(0, action.delayTicks);
|
||||
int targetTimes = Math.max(0, action.times);
|
||||
int completed = 0;
|
||||
|
||||
if (startDelay > 0) waitBreakClientTicks(startDelay);
|
||||
|
||||
final boolean[] started = { false };
|
||||
final boolean useNextSteps = action.interact && action.runNextSteps;
|
||||
final boolean[] nextStepsFired = { false };
|
||||
final boolean[] missingNextStepsWarned = { false };
|
||||
AutismInstaBreakRenderer.setTarget(target);
|
||||
long lastTick = -1L;
|
||||
try {
|
||||
while (MacroExecutor.isCurrentRunActive() && isActionStillInCurrentMacro(action)) {
|
||||
long now = AutismSharedState.get().getClientTickCounter();
|
||||
if (now == lastTick) {
|
||||
Thread.sleep(1);
|
||||
continue;
|
||||
}
|
||||
lastTick = now;
|
||||
|
||||
int result;
|
||||
if (!started[0]) {
|
||||
result = useNextSteps
|
||||
? startBreakWithNextSteps(mc, action, target, direction, started, nextStepsFired, missingNextStepsWarned)
|
||||
: MacroExecutor.callOnClientThread(mc, () -> startBreakOnClient(mc, action, target, direction, started), -1, action.isTickAligned());
|
||||
} else if (action.interact && action.interactTiming == InteractTiming.CUSTOM) {
|
||||
result = useNextSteps
|
||||
? breakCustomTickWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
|
||||
: breakCustomTick(mc, action, target, direction);
|
||||
} else {
|
||||
result = useNextSteps
|
||||
? breakContinueWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
|
||||
: MacroExecutor.callOnClientThread(mc, () -> breakContinueOnClient(mc, action, target, direction), -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
return;
|
||||
} else if (result == 1) {
|
||||
boolean completedStartedBreak = started[0];
|
||||
if (useNextSteps && completedStartedBreak) {
|
||||
runBreakNextStepsAfterCompletion(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
} else if (action.interact && action.interactTiming == InteractTiming.AFTER_PLUS) {
|
||||
MacroExecutor.waitOneTick();
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
}
|
||||
completed++;
|
||||
MacroExecutor.setCurrentStatus("Break " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
if (targetTimes > 0 && completed >= targetTimes) return;
|
||||
started[0] = false;
|
||||
nextStepsFired[0] = false;
|
||||
waitForBreakSolid(mc, target);
|
||||
} else {
|
||||
MacroExecutor.setCurrentStatus("Break " + target.getX() + "," + target.getY() + "," + target.getZ()
|
||||
+ " " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
final boolean wasMining = started[0];
|
||||
MacroExecutor.runOnClientThread(mc, () -> {
|
||||
if (wasMining && mc.gameMode != null && mc.gameMode.isDestroying()) mc.gameMode.stopDestroyBlock();
|
||||
if (action.sneak) releaseMacroSneak(mc, action.sneakMode);
|
||||
}, action.isTickAligned());
|
||||
AutismInstaBreakRenderer.clearTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static int startBreakWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] started, boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
MacroExecutor.BreakStartPlan plan = MacroExecutor.callOnClientThread(mc, () -> prepareBreakStartOnClient(mc, action, pos), new MacroExecutor.BreakStartPlan(-1, false, false));
|
||||
if (plan.result() != 0) return plan.result();
|
||||
|
||||
if (plan.instant() && plan.interactFirst()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!MacroExecutor.isCurrentRunActive()) return -1;
|
||||
}
|
||||
|
||||
int result = MacroExecutor.callOnClientThread(mc, () -> startPreparedBreakOnClient(mc, action, pos, dir, started), -1, action.isTickAligned());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MacroExecutor.BreakStartPlan prepareBreakStartOnClient(Minecraft mc, BreakAction action, BlockPos pos) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) {
|
||||
return new MacroExecutor.BreakStartPlan(-1, false, false);
|
||||
}
|
||||
if (mc.level.isOutsideBuildHeight(pos)) return new MacroExecutor.BreakStartPlan(1, false, false);
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new MacroExecutor.BreakStartPlan(1, false, false);
|
||||
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
if (action.autoTool) {
|
||||
AutismAutoTool.equipBestTool(mc, state, action.considerInventory, true);
|
||||
state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new MacroExecutor.BreakStartPlan(1, false, false);
|
||||
}
|
||||
|
||||
float startDelta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
boolean instant = startDelta >= 1.0f;
|
||||
boolean interactFirst = action.interact && (action.interactTiming == InteractTiming.BEFORE
|
||||
|| action.interactTiming == InteractTiming.WITH
|
||||
|| (action.interactTiming == InteractTiming.CUSTOM && action.interactCustomMs < 0));
|
||||
return new MacroExecutor.BreakStartPlan(0, instant, interactFirst);
|
||||
}
|
||||
|
||||
private static int startPreparedBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, boolean[] started) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
if (mc.level.isOutsideBuildHeight(pos) || mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.startDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
started[0] = true;
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int startBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, boolean[] started) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir() || mc.level.isOutsideBuildHeight(pos)) return 1;
|
||||
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
if (action.autoTool) {
|
||||
AutismAutoTool.equipBestTool(mc, state, action.considerInventory, true);
|
||||
state = mc.level.getBlockState(pos);
|
||||
}
|
||||
|
||||
float startDelta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
boolean instant = startDelta >= 1.0f;
|
||||
boolean interactFirst = action.interact && (action.interactTiming == InteractTiming.BEFORE
|
||||
|| action.interactTiming == InteractTiming.WITH
|
||||
|| (action.interactTiming == InteractTiming.CUSTOM && action.interactCustomMs < 0));
|
||||
if (instant && interactFirst) sendBlockInteract(mc, pos, dir);
|
||||
mc.gameMode.startDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
started[0] = true;
|
||||
if (instant && action.interact && !interactFirst && action.interactTiming != InteractTiming.AFTER_PLUS) sendBlockInteract(mc, pos, dir);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakContinueWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
MacroExecutor.BreakContinuePlan plan = MacroExecutor.callOnClientThread(mc, () -> inspectBreakContinueOnClient(mc, action, pos), new MacroExecutor.BreakContinuePlan(-1, false, false));
|
||||
if (plan.result() != 0) return plan.result();
|
||||
|
||||
InteractTiming timing = action.interactTiming;
|
||||
if (timing == InteractTiming.BEFORE && plan.breaksNextTick()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!MacroExecutor.isCurrentRunActive()) return -1;
|
||||
}
|
||||
if (timing == InteractTiming.WITH && plan.breaksThisTick()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!MacroExecutor.isCurrentRunActive()) return -1;
|
||||
}
|
||||
|
||||
int result = MacroExecutor.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MacroExecutor.BreakContinuePlan inspectBreakContinueOnClient(Minecraft mc, BreakAction action, BlockPos pos) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) {
|
||||
return new MacroExecutor.BreakContinuePlan(-1, false, false);
|
||||
}
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new MacroExecutor.BreakContinuePlan(1, false, false);
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
|
||||
boolean breaksThisTick = willBreakThisTick(mc, pos, state);
|
||||
boolean breaksNextTick = !breaksThisTick && willBreakNextTick(mc, pos, state);
|
||||
return new MacroExecutor.BreakContinuePlan(0, breaksThisTick, breaksNextTick);
|
||||
}
|
||||
|
||||
private static int continueBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakContinueOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
|
||||
boolean breaksThisTick = willBreakThisTick(mc, pos, state);
|
||||
boolean breaksNextTick = !breaksThisTick && willBreakNextTick(mc, pos, state);
|
||||
InteractTiming t = action.interactTiming;
|
||||
if (action.interact && t == InteractTiming.BEFORE && breaksNextTick) sendBlockInteract(mc, pos, dir);
|
||||
if (action.interact && t == InteractTiming.WITH && breaksThisTick) sendBlockInteract(mc, pos, dir);
|
||||
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
|
||||
if (action.interact && t == InteractTiming.AFTER && breaksThisTick) sendBlockInteract(mc, pos, dir);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakCustomTickWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
boolean willBreak = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.player == null) return Boolean.FALSE;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return Boolean.FALSE;
|
||||
return willBreakThisTick(mc, pos, state);
|
||||
}, Boolean.FALSE));
|
||||
|
||||
if (!willBreak) {
|
||||
return MacroExecutor.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
int broke;
|
||||
if (action.interactCustomMs < 0) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!MacroExecutor.isCurrentRunActive()) return -1;
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
} else {
|
||||
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
}
|
||||
return broke;
|
||||
}
|
||||
|
||||
private static int breakCustomTick(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) throws InterruptedException {
|
||||
boolean willBreak = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.player == null) return Boolean.FALSE;
|
||||
BlockState s = mc.level.getBlockState(pos);
|
||||
if (s.isAir()) return Boolean.FALSE;
|
||||
return willBreakThisTick(mc, pos, s);
|
||||
}, Boolean.FALSE));
|
||||
|
||||
if (!willBreak) {
|
||||
|
||||
return MacroExecutor.callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}, -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
int broke;
|
||||
if (action.interactCustomMs < 0) {
|
||||
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
} else {
|
||||
|
||||
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
|
||||
}
|
||||
return broke;
|
||||
}
|
||||
|
||||
private static int breakAndDetectOnClient(Minecraft mc, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static boolean willBreakThisTick(Minecraft mc, BlockPos pos, BlockState state) {
|
||||
float progress = (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor acc) ? acc.autism$getDestroyProgress() : 0f;
|
||||
float delta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
return progress > 0f && (progress + delta) >= 1.0f;
|
||||
}
|
||||
|
||||
private static boolean willBreakNextTick(Minecraft mc, BlockPos pos, BlockState state) {
|
||||
float progress = (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor acc) ? acc.autism$getDestroyProgress() : 0f;
|
||||
float delta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
return progress > 0f && (progress + 2f * delta) >= 1.0f;
|
||||
}
|
||||
|
||||
private static void runBreakNextStepsOnce(Minecraft mc, BreakAction action, boolean[] fired, boolean[] missingWarned) throws InterruptedException {
|
||||
if (fired != null && fired[0]) return;
|
||||
java.util.List<MacroAction> actions = action.getNextActions();
|
||||
if (actions == null || actions.isEmpty()) {
|
||||
if (missingWarned != null && !missingWarned[0]) {
|
||||
missingWarned[0] = true;
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak: no next steps found. Add action(s) after this Break step.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fired != null) fired[0] = true;
|
||||
action.markNextActionsRan();
|
||||
String names = actions.size() == 1 ? actions.get(0).getDisplayName() : actions.size() + " steps";
|
||||
MacroExecutor.setCurrentStatus("Break: next " + names);
|
||||
AutismModule module = AutismModule.get();
|
||||
boolean previousSuppressPostGui = Boolean.TRUE.equals(MacroExecutor.SUPPRESS_POST_GUI_AFTER.get());
|
||||
try {
|
||||
MacroExecutor.SUPPRESS_POST_GUI_AFTER.set(true);
|
||||
for (MacroAction next : actions) {
|
||||
if (next == null || !next.isEnabled() || !MacroExecutor.isCurrentRunActive()) continue;
|
||||
try {
|
||||
MacroExecutor.executeSingleActionWithWaits(mc, next, module);
|
||||
} catch (InterruptedException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak next step failed (" + next.getDisplayName() + "): " + MacroRace.safeThrowableMessage(t));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
MacroExecutor.SUPPRESS_POST_GUI_AFTER.set(previousSuppressPostGui);
|
||||
}
|
||||
}
|
||||
|
||||
private static void runBreakNextStepsAfterCompletion(Minecraft mc, BreakAction action, boolean[] fired,
|
||||
boolean[] missingWarned) throws InterruptedException {
|
||||
if (!action.interact || !action.runNextSteps || action.interactTiming == null) return;
|
||||
switch (action.interactTiming) {
|
||||
case AFTER -> runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
case AFTER_PLUS -> {
|
||||
MacroExecutor.waitOneTick();
|
||||
runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
}
|
||||
case CUSTOM -> {
|
||||
if (action.interactCustomMs >= 0) {
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendBlockInteract(Minecraft mc, BlockPos pos, Direction dir) {
|
||||
if (mc.gameMode == null || mc.player == null) return;
|
||||
Vec3 hit = Vec3.atCenterOf(pos).add(dir.getStepX() * 0.5, dir.getStepY() * 0.5, dir.getStepZ() * 0.5);
|
||||
BlockHitResult blockHit = new BlockHitResult(hit, dir, pos, false);
|
||||
mc.gameMode.useItemOn(mc.player, InteractionHand.MAIN_HAND, blockHit);
|
||||
}
|
||||
|
||||
private static void waitForBreakSolid(Minecraft mc, BlockPos pos) throws InterruptedException {
|
||||
while (MacroExecutor.isCurrentRunActive()) {
|
||||
if (!isInstaBreakAir(mc, pos)) return;
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitBreakClientTicks(int ticks) throws InterruptedException {
|
||||
long start = AutismSharedState.get().getClientTickCounter();
|
||||
while (MacroExecutor.isCurrentRunActive() && (AutismSharedState.get().getClientTickCounter() - start) < ticks) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void holdMacroSneak(Minecraft mc, String mode) {
|
||||
autismclient.util.AutismMacroSneak.hold(mc, mode);
|
||||
}
|
||||
|
||||
private static void releaseMacroSneak(Minecraft mc, String mode) {
|
||||
autismclient.util.AutismMacroSneak.release(mc, mode);
|
||||
if (!autismclient.util.AutismMacroSneak.isPacket(mode)) MacroExecutor.applyAggregateSneakState(mc);
|
||||
}
|
||||
}
|
||||
|
|
@ -243,8 +243,8 @@ public class MacroExecutor {
|
|||
return new InlineNextActions(java.util.List.of(), -1);
|
||||
}
|
||||
}
|
||||
private record BreakStartPlan(int result, boolean instant, boolean interactFirst) {}
|
||||
private record BreakContinuePlan(int result, boolean breaksThisTick, boolean breaksNextTick) {}
|
||||
record BreakStartPlan(int result, boolean instant, boolean interactFirst) {}
|
||||
record BreakContinuePlan(int result, boolean breaksThisTick, boolean breaksNextTick) {}
|
||||
record MacroEvent(Packet<?> packet, String direction, long nanoTime, ChatCapture chatCapture,
|
||||
java.util.Map<String, MacroValue> captures) {
|
||||
MacroEvent(Packet<?> packet, String direction, long nanoTime, ChatCapture chatCapture) {
|
||||
|
|
@ -713,7 +713,7 @@ public class MacroExecutor {
|
|||
});
|
||||
}
|
||||
|
||||
private static void applyAggregateSneakState(Minecraft mc) {
|
||||
static void applyAggregateSneakState(Minecraft mc) {
|
||||
if (mc == null || mc.options == null || mc.options.keyShift == null) return;
|
||||
boolean held = hasPersistentInput(SneakAction.class);
|
||||
mc.options.keyShift.setDown(held);
|
||||
|
|
@ -1497,7 +1497,7 @@ public class MacroExecutor {
|
|||
runMineAction(mc, mna);
|
||||
}
|
||||
else if (action instanceof InstaBreakAction) {
|
||||
runInstaBreakAction(mc, (InstaBreakAction) action);
|
||||
MacroBreak.runInstaBreakAction(mc, (InstaBreakAction) action);
|
||||
}
|
||||
else if (action instanceof BreakAction breakAction) {
|
||||
InlineNextActions nextActions = InlineNextActions.empty();
|
||||
|
|
@ -1505,7 +1505,7 @@ public class MacroExecutor {
|
|||
nextActions = collectInlineNextActions(macro.actions, i);
|
||||
breakAction.setNextActions(nextActions.actions());
|
||||
}
|
||||
runBreakAction(mc, breakAction);
|
||||
MacroBreak.runBreakAction(mc, breakAction);
|
||||
if (breakAction.didRunNextActions() && nextActions.lastIndex() > i) i = nextActions.lastIndex();
|
||||
}
|
||||
|
||||
|
|
@ -2358,9 +2358,9 @@ public class MacroExecutor {
|
|||
MineAction mna = (MineAction) action;
|
||||
runMineAction(mc, mna);
|
||||
} else if (action instanceof InstaBreakAction) {
|
||||
runInstaBreakAction(mc, (InstaBreakAction) action);
|
||||
MacroBreak.runInstaBreakAction(mc, (InstaBreakAction) action);
|
||||
} else if (action instanceof BreakAction) {
|
||||
runBreakAction(mc, (BreakAction) action);
|
||||
MacroBreak.runBreakAction(mc, (BreakAction) action);
|
||||
} else if (action instanceof PlaceAction) {
|
||||
runPlaceAction(mc, (PlaceAction) action);
|
||||
} else if (action instanceof UseItemAction) {
|
||||
|
|
@ -2660,531 +2660,6 @@ public class MacroExecutor {
|
|||
waitForCondition(tickFuture);
|
||||
}
|
||||
|
||||
private static void runInstaBreakAction(Minecraft mc, InstaBreakAction action) throws InterruptedException {
|
||||
if (mc == null || mc.player == null || mc.level == null || mc.getConnection() == null || mc.gameMode == null) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cInstaBreak: missing world or connection");
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos target = action.blockPos == null ? BlockPos.ZERO : action.blockPos;
|
||||
Direction direction = action.direction == null ? Direction.UP : action.direction;
|
||||
int delayTicks = Math.max(0, action.delayTicks);
|
||||
int targetTimes = Math.max(0, action.times);
|
||||
int completed = 0;
|
||||
boolean wasSolid = !isInstaBreakAir(mc, target);
|
||||
|
||||
if (!ensureInstaBreakPickaxe(mc, action)) return;
|
||||
|
||||
AutismInstaBreakRenderer.setTarget(target);
|
||||
try {
|
||||
long lastAttemptTick = AutismSharedState.get().getClientTickCounter() - (delayTicks + 1L);
|
||||
long lastSneakTick = Long.MIN_VALUE;
|
||||
while (isCurrentRunActive() && isActionStillInCurrentMacro(action)) {
|
||||
|
||||
if (action.sneak) {
|
||||
long sneakTick = AutismSharedState.get().getClientTickCounter();
|
||||
if (sneakTick != lastSneakTick) {
|
||||
lastSneakTick = sneakTick;
|
||||
final String sneakMode = action.sneakMode;
|
||||
runOnClientThread(mc, () -> holdMacroSneak(mc, sneakMode), action.isTickAligned());
|
||||
}
|
||||
}
|
||||
|
||||
boolean isAir = isInstaBreakAir(mc, target);
|
||||
if (wasSolid && isAir) {
|
||||
completed++;
|
||||
setCurrentStatus("InstaBreak " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
if (targetTimes > 0 && completed >= targetTimes) return;
|
||||
wasSolid = false;
|
||||
} else if (!isAir) {
|
||||
wasSolid = true;
|
||||
}
|
||||
|
||||
if (!isAir) {
|
||||
long currentTick = AutismSharedState.get().getClientTickCounter();
|
||||
if (currentTick != lastAttemptTick && (currentTick - lastAttemptTick) >= delayTicks) {
|
||||
lastAttemptTick = currentTick;
|
||||
if (!ensureInstaBreakPickaxe(mc, action)) return;
|
||||
if (action.interact) {
|
||||
|
||||
InteractTiming t = action.interactTiming;
|
||||
boolean interactFirst = t == InteractTiming.BEFORE || t == InteractTiming.WITH
|
||||
|| (t == InteractTiming.CUSTOM && action.interactCustomMs < 0);
|
||||
long ns = t == InteractTiming.CUSTOM
|
||||
? Math.abs((long) action.interactCustomMs) * 1_000_000L : 0L;
|
||||
if (interactFirst) {
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
} else if (t == InteractTiming.AFTER_PLUS) {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
waitOneTick();
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
} else {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
}
|
||||
} else {
|
||||
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentStatus("InstaBreak " + target.getX() + "," + target.getY() + "," + target.getZ()
|
||||
+ " " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
|
||||
Thread.sleep(1);
|
||||
}
|
||||
} finally {
|
||||
if (action.sneak) {
|
||||
final String sneakMode = action.sneakMode;
|
||||
try {
|
||||
runOnClientThread(mc, () -> releaseMacroSneak(mc, sneakMode));
|
||||
} catch (InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
AutismInstaBreakRenderer.clearTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInstaBreakAir(Minecraft mc, BlockPos pos) {
|
||||
|
||||
return mc.level == null || mc.level.isOutsideBuildHeight(pos) || mc.level.getBlockState(pos).isAir();
|
||||
}
|
||||
|
||||
private static boolean isActionStillInCurrentMacro(MacroAction action) {
|
||||
RunState run = CURRENT_RUN.get();
|
||||
if (run == null || run.macro == null || run.macro.actions == null) return true;
|
||||
return run.macro.actions.contains(action);
|
||||
}
|
||||
|
||||
private static boolean ensureInstaBreakPickaxe(Minecraft mc, InstaBreakAction action) throws InterruptedException {
|
||||
|
||||
return callOnClientThread(mc, () -> {
|
||||
if (mc.player == null) return false;
|
||||
if (mc.player.getMainHandItem().is(ItemTags.PICKAXES)) return true;
|
||||
if (!action.autoPickaxe) return false;
|
||||
|
||||
int preferred = Math.max(0, Math.min(8, mc.player.getInventory().getSelectedSlot()));
|
||||
for (int slot = 0; slot < 9; slot++) {
|
||||
if (mc.player.getInventory().getItem(slot).is(ItemTags.PICKAXES)) {
|
||||
AutismInventoryHelper.selectHotbarSlot(mc, slot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int slot = 9; slot < 36; slot++) {
|
||||
if (mc.player.getInventory().getItem(slot).is(ItemTags.PICKAXES)) {
|
||||
if (!AutismInventoryHelper.swapInventorySlots(mc, slot, preferred)) return false;
|
||||
AutismInventoryHelper.selectHotbarSlot(mc, preferred);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, false, action.isTickAligned());
|
||||
}
|
||||
|
||||
private static void sendInstaBreakAttempt(Minecraft mc, BlockPos pos, Direction direction, boolean tickAligned) throws InterruptedException {
|
||||
runOnClientThread(mc, () -> {
|
||||
if (mc.player == null || mc.level == null || mc.gameMode == null || mc.getConnection() == null) return;
|
||||
BlockPos blockPos = pos.immutable();
|
||||
Direction dir = direction == null ? Direction.UP : direction;
|
||||
|
||||
if (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor accessor) {
|
||||
accessor.autism$startPrediction(mc.level, sequence -> new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, dir, sequence));
|
||||
accessor.autism$startPrediction(mc.level, sequence -> new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, blockPos, dir, sequence));
|
||||
} else {
|
||||
|
||||
mc.getConnection().send(new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, blockPos, dir));
|
||||
mc.getConnection().send(new ServerboundPlayerActionPacket(
|
||||
ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, blockPos, dir));
|
||||
}
|
||||
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
}, tickAligned);
|
||||
}
|
||||
|
||||
private static void runBreakAction(Minecraft mc, BreakAction action) throws InterruptedException {
|
||||
if (mc == null || mc.player == null || mc.level == null || mc.getConnection() == null || mc.gameMode == null) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak: missing world or connection");
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockPos target = action.blockPos == null ? BlockPos.ZERO : action.blockPos;
|
||||
final Direction direction = action.direction == null ? Direction.UP : action.direction;
|
||||
int startDelay = Math.max(0, action.delayTicks);
|
||||
int targetTimes = Math.max(0, action.times);
|
||||
int completed = 0;
|
||||
|
||||
if (startDelay > 0) waitBreakClientTicks(startDelay);
|
||||
|
||||
final boolean[] started = { false };
|
||||
final boolean useNextSteps = action.interact && action.runNextSteps;
|
||||
final boolean[] nextStepsFired = { false };
|
||||
final boolean[] missingNextStepsWarned = { false };
|
||||
AutismInstaBreakRenderer.setTarget(target);
|
||||
long lastTick = -1L;
|
||||
try {
|
||||
while (isCurrentRunActive() && isActionStillInCurrentMacro(action)) {
|
||||
long now = AutismSharedState.get().getClientTickCounter();
|
||||
if (now == lastTick) {
|
||||
Thread.sleep(1);
|
||||
continue;
|
||||
}
|
||||
lastTick = now;
|
||||
|
||||
int result;
|
||||
if (!started[0]) {
|
||||
result = useNextSteps
|
||||
? startBreakWithNextSteps(mc, action, target, direction, started, nextStepsFired, missingNextStepsWarned)
|
||||
: callOnClientThread(mc, () -> startBreakOnClient(mc, action, target, direction, started), -1, action.isTickAligned());
|
||||
} else if (action.interact && action.interactTiming == InteractTiming.CUSTOM) {
|
||||
result = useNextSteps
|
||||
? breakCustomTickWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
|
||||
: breakCustomTick(mc, action, target, direction);
|
||||
} else {
|
||||
result = useNextSteps
|
||||
? breakContinueWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
|
||||
: callOnClientThread(mc, () -> breakContinueOnClient(mc, action, target, direction), -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
return;
|
||||
} else if (result == 1) {
|
||||
boolean completedStartedBreak = started[0];
|
||||
if (useNextSteps && completedStartedBreak) {
|
||||
runBreakNextStepsAfterCompletion(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
} else if (action.interact && action.interactTiming == InteractTiming.AFTER_PLUS) {
|
||||
waitOneTick();
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
|
||||
}
|
||||
completed++;
|
||||
setCurrentStatus("Break " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
if (targetTimes > 0 && completed >= targetTimes) return;
|
||||
started[0] = false;
|
||||
nextStepsFired[0] = false;
|
||||
waitForBreakSolid(mc, target);
|
||||
} else {
|
||||
setCurrentStatus("Break " + target.getX() + "," + target.getY() + "," + target.getZ()
|
||||
+ " " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
final boolean wasMining = started[0];
|
||||
runOnClientThread(mc, () -> {
|
||||
if (wasMining && mc.gameMode != null && mc.gameMode.isDestroying()) mc.gameMode.stopDestroyBlock();
|
||||
if (action.sneak) releaseMacroSneak(mc, action.sneakMode);
|
||||
}, action.isTickAligned());
|
||||
AutismInstaBreakRenderer.clearTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static int startBreakWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] started, boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
BreakStartPlan plan = callOnClientThread(mc, () -> prepareBreakStartOnClient(mc, action, pos), new BreakStartPlan(-1, false, false));
|
||||
if (plan.result() != 0) return plan.result();
|
||||
|
||||
if (plan.instant() && plan.interactFirst()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!isCurrentRunActive()) return -1;
|
||||
}
|
||||
|
||||
int result = callOnClientThread(mc, () -> startPreparedBreakOnClient(mc, action, pos, dir, started), -1, action.isTickAligned());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BreakStartPlan prepareBreakStartOnClient(Minecraft mc, BreakAction action, BlockPos pos) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) {
|
||||
return new BreakStartPlan(-1, false, false);
|
||||
}
|
||||
if (mc.level.isOutsideBuildHeight(pos)) return new BreakStartPlan(1, false, false);
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new BreakStartPlan(1, false, false);
|
||||
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
if (action.autoTool) {
|
||||
AutismAutoTool.equipBestTool(mc, state, action.considerInventory, true);
|
||||
state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new BreakStartPlan(1, false, false);
|
||||
}
|
||||
|
||||
float startDelta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
boolean instant = startDelta >= 1.0f;
|
||||
boolean interactFirst = action.interact && (action.interactTiming == InteractTiming.BEFORE
|
||||
|| action.interactTiming == InteractTiming.WITH
|
||||
|| (action.interactTiming == InteractTiming.CUSTOM && action.interactCustomMs < 0));
|
||||
return new BreakStartPlan(0, instant, interactFirst);
|
||||
}
|
||||
|
||||
private static int startPreparedBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, boolean[] started) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
if (mc.level.isOutsideBuildHeight(pos) || mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.startDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
started[0] = true;
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int startBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, boolean[] started) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir() || mc.level.isOutsideBuildHeight(pos)) return 1;
|
||||
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
if (action.autoTool) {
|
||||
AutismAutoTool.equipBestTool(mc, state, action.considerInventory, true);
|
||||
state = mc.level.getBlockState(pos);
|
||||
}
|
||||
|
||||
float startDelta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
boolean instant = startDelta >= 1.0f;
|
||||
boolean interactFirst = action.interact && (action.interactTiming == InteractTiming.BEFORE
|
||||
|| action.interactTiming == InteractTiming.WITH
|
||||
|| (action.interactTiming == InteractTiming.CUSTOM && action.interactCustomMs < 0));
|
||||
if (instant && interactFirst) sendBlockInteract(mc, pos, dir);
|
||||
mc.gameMode.startDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
started[0] = true;
|
||||
if (instant && action.interact && !interactFirst && action.interactTiming != InteractTiming.AFTER_PLUS) sendBlockInteract(mc, pos, dir);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakContinueWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
BreakContinuePlan plan = callOnClientThread(mc, () -> inspectBreakContinueOnClient(mc, action, pos), new BreakContinuePlan(-1, false, false));
|
||||
if (plan.result() != 0) return plan.result();
|
||||
|
||||
InteractTiming timing = action.interactTiming;
|
||||
if (timing == InteractTiming.BEFORE && plan.breaksNextTick()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!isCurrentRunActive()) return -1;
|
||||
}
|
||||
if (timing == InteractTiming.WITH && plan.breaksThisTick()) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!isCurrentRunActive()) return -1;
|
||||
}
|
||||
|
||||
int result = callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BreakContinuePlan inspectBreakContinueOnClient(Minecraft mc, BreakAction action, BlockPos pos) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) {
|
||||
return new BreakContinuePlan(-1, false, false);
|
||||
}
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return new BreakContinuePlan(1, false, false);
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
|
||||
boolean breaksThisTick = willBreakThisTick(mc, pos, state);
|
||||
boolean breaksNextTick = !breaksThisTick && willBreakNextTick(mc, pos, state);
|
||||
return new BreakContinuePlan(0, breaksThisTick, breaksNextTick);
|
||||
}
|
||||
|
||||
private static int continueBreakOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakContinueOnClient(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null || mc.getConnection() == null) return -1;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
|
||||
boolean breaksThisTick = willBreakThisTick(mc, pos, state);
|
||||
boolean breaksNextTick = !breaksThisTick && willBreakNextTick(mc, pos, state);
|
||||
InteractTiming t = action.interactTiming;
|
||||
if (action.interact && t == InteractTiming.BEFORE && breaksNextTick) sendBlockInteract(mc, pos, dir);
|
||||
if (action.interact && t == InteractTiming.WITH && breaksThisTick) sendBlockInteract(mc, pos, dir);
|
||||
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
|
||||
if (action.interact && t == InteractTiming.AFTER && breaksThisTick) sendBlockInteract(mc, pos, dir);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int breakCustomTickWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
|
||||
boolean[] nextStepsFired,
|
||||
boolean[] missingNextStepsWarned) throws InterruptedException {
|
||||
boolean willBreak = Boolean.TRUE.equals(callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.player == null) return Boolean.FALSE;
|
||||
BlockState state = mc.level.getBlockState(pos);
|
||||
if (state.isAir()) return Boolean.FALSE;
|
||||
return willBreakThisTick(mc, pos, state);
|
||||
}, Boolean.FALSE));
|
||||
|
||||
if (!willBreak) {
|
||||
return callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
int broke;
|
||||
if (action.interactCustomMs < 0) {
|
||||
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
|
||||
if (!isCurrentRunActive()) return -1;
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
broke = callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
} else {
|
||||
broke = callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
}
|
||||
return broke;
|
||||
}
|
||||
|
||||
private static int breakCustomTick(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) throws InterruptedException {
|
||||
boolean willBreak = Boolean.TRUE.equals(callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.player == null) return Boolean.FALSE;
|
||||
BlockState s = mc.level.getBlockState(pos);
|
||||
if (s.isAir()) return Boolean.FALSE;
|
||||
return willBreakThisTick(mc, pos, s);
|
||||
}, Boolean.FALSE));
|
||||
|
||||
if (!willBreak) {
|
||||
|
||||
return callOnClientThread(mc, () -> {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
if (action.sneak) holdMacroSneak(mc, action.sneakMode);
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}, -1, action.isTickAligned());
|
||||
}
|
||||
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
int broke;
|
||||
if (action.interactCustomMs < 0) {
|
||||
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
broke = callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
} else {
|
||||
|
||||
broke = callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
|
||||
}
|
||||
return broke;
|
||||
}
|
||||
|
||||
private static int breakAndDetectOnClient(Minecraft mc, BlockPos pos, Direction dir) {
|
||||
if (mc.level == null || mc.gameMode == null || mc.player == null) return -1;
|
||||
if (mc.level.getBlockState(pos).isAir()) return 1;
|
||||
mc.gameMode.continueDestroyBlock(pos, dir);
|
||||
mc.player.swing(InteractionHand.MAIN_HAND);
|
||||
return mc.level.getBlockState(pos).isAir() ? 1 : 0;
|
||||
}
|
||||
|
||||
private static boolean willBreakThisTick(Minecraft mc, BlockPos pos, BlockState state) {
|
||||
float progress = (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor acc) ? acc.autism$getDestroyProgress() : 0f;
|
||||
float delta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
return progress > 0f && (progress + delta) >= 1.0f;
|
||||
}
|
||||
|
||||
private static boolean willBreakNextTick(Minecraft mc, BlockPos pos, BlockState state) {
|
||||
float progress = (mc.gameMode instanceof AutismMultiPlayerGameModeAccessor acc) ? acc.autism$getDestroyProgress() : 0f;
|
||||
float delta = state.getDestroyProgress(mc.player, mc.player.level(), pos);
|
||||
return progress > 0f && (progress + 2f * delta) >= 1.0f;
|
||||
}
|
||||
|
||||
private static void runBreakNextStepsOnce(Minecraft mc, BreakAction action, boolean[] fired, boolean[] missingWarned) throws InterruptedException {
|
||||
if (fired != null && fired[0]) return;
|
||||
java.util.List<MacroAction> actions = action.getNextActions();
|
||||
if (actions == null || actions.isEmpty()) {
|
||||
if (missingWarned != null && !missingWarned[0]) {
|
||||
missingWarned[0] = true;
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak: no next steps found. Add action(s) after this Break step.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fired != null) fired[0] = true;
|
||||
action.markNextActionsRan();
|
||||
String names = actions.size() == 1 ? actions.get(0).getDisplayName() : actions.size() + " steps";
|
||||
setCurrentStatus("Break: next " + names);
|
||||
AutismModule module = AutismModule.get();
|
||||
boolean previousSuppressPostGui = Boolean.TRUE.equals(SUPPRESS_POST_GUI_AFTER.get());
|
||||
try {
|
||||
SUPPRESS_POST_GUI_AFTER.set(true);
|
||||
for (MacroAction next : actions) {
|
||||
if (next == null || !next.isEnabled() || !isCurrentRunActive()) continue;
|
||||
try {
|
||||
executeSingleActionWithWaits(mc, next, module);
|
||||
} catch (InterruptedException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
AutismClientMessaging.sendPrefixed("\u00a7cBreak next step failed (" + next.getDisplayName() + "): " + MacroRace.safeThrowableMessage(t));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
SUPPRESS_POST_GUI_AFTER.set(previousSuppressPostGui);
|
||||
}
|
||||
}
|
||||
|
||||
private static void runBreakNextStepsAfterCompletion(Minecraft mc, BreakAction action, boolean[] fired,
|
||||
boolean[] missingWarned) throws InterruptedException {
|
||||
if (!action.interact || !action.runNextSteps || action.interactTiming == null) return;
|
||||
switch (action.interactTiming) {
|
||||
case AFTER -> runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
case AFTER_PLUS -> {
|
||||
waitOneTick();
|
||||
runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
}
|
||||
case CUSTOM -> {
|
||||
if (action.interactCustomMs >= 0) {
|
||||
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
runBreakNextStepsOnce(mc, action, fired, missingWarned);
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendBlockInteract(Minecraft mc, BlockPos pos, Direction dir) {
|
||||
if (mc.gameMode == null || mc.player == null) return;
|
||||
Vec3 hit = Vec3.atCenterOf(pos).add(dir.getStepX() * 0.5, dir.getStepY() * 0.5, dir.getStepZ() * 0.5);
|
||||
BlockHitResult blockHit = new BlockHitResult(hit, dir, pos, false);
|
||||
mc.gameMode.useItemOn(mc.player, InteractionHand.MAIN_HAND, blockHit);
|
||||
}
|
||||
|
||||
private static void waitForBreakSolid(Minecraft mc, BlockPos pos) throws InterruptedException {
|
||||
while (isCurrentRunActive()) {
|
||||
if (!isInstaBreakAir(mc, pos)) return;
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitBreakClientTicks(int ticks) throws InterruptedException {
|
||||
long start = AutismSharedState.get().getClientTickCounter();
|
||||
while (isCurrentRunActive() && (AutismSharedState.get().getClientTickCounter() - start) < ticks) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void holdMacroSneak(Minecraft mc, String mode) {
|
||||
autismclient.util.AutismMacroSneak.hold(mc, mode);
|
||||
}
|
||||
|
||||
private static void releaseMacroSneak(Minecraft mc, String mode) {
|
||||
autismclient.util.AutismMacroSneak.release(mc, mode);
|
||||
if (!autismclient.util.AutismMacroSneak.isPacket(mode)) applyAggregateSneakState(mc);
|
||||
}
|
||||
|
||||
static void runOnClientThread(Minecraft mc, Runnable runnable) throws InterruptedException {
|
||||
if (PackHideState.isHardLocked()) return;
|
||||
|
|
@ -3352,24 +2827,24 @@ public class MacroExecutor {
|
|||
|
||||
if (interactFirst) {
|
||||
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
|
||||
} else if (t == InteractTiming.WITH) {
|
||||
|
||||
runOnClientThread(mc, () -> {
|
||||
try { action.execute(mc); } catch (Exception e) { AutismClientAddon.LOG.debug("[Autism] Macro WITH-interact action failed", e); }
|
||||
sendBlockInteract(mc, placePos, face);
|
||||
MacroBreak.sendBlockInteract(mc, placePos, face);
|
||||
}, action.isTickAligned());
|
||||
} else if (t == InteractTiming.AFTER_PLUS) {
|
||||
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
|
||||
waitOneTick();
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
} else {
|
||||
|
||||
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
|
||||
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
|
||||
runOnClientThread(mc, () -> sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue