Refactor: extract MacroClientThread from MacroExecutor (upstream #4)

Move 8 client-thread/tick dispatch methods plus the TICK_ALIGNED
queue verbatim into MacroClientThread. drainTickAligned kept as public
delegate for the mixin caller; run/call variants re-pointed across all
helpers. All bodies verified identical against HEAD modulo mechanical
MacroExecutor./MacroClientThread. qualification.
This commit is contained in:
sectersion 2026-10-11 16:24:21 +01:00
parent 79c1e81cc6
commit 61938e7774
8 changed files with 273 additions and 255 deletions

View file

@ -19,7 +19,7 @@ final class MacroActionRunner {
if (!(action instanceof RaycastAim aim) || !aim.isRaycast()) return; if (!(action instanceof RaycastAim aim) || !aim.isRaycast()) return;
autismclient.util.AutismRotationUtil.Rotation rotation; autismclient.util.AutismRotationUtil.Rotation rotation;
try { try {
rotation = MacroExecutor.callOnClientThread(mc, () -> MacroRaycastAim.aimFor(mc, aim.raycastTarget(mc)), null); rotation = MacroClientThread.callOnClientThread(mc, () -> MacroRaycastAim.aimFor(mc, aim.raycastTarget(mc)), null);
} catch (InterruptedException interrupted) { } catch (InterruptedException interrupted) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;
@ -95,7 +95,7 @@ final class MacroActionRunner {
} }
private static boolean canRunTargetInteractionNow(Minecraft mc, MacroAction action) throws InterruptedException { private static boolean canRunTargetInteractionNow(Minecraft mc, MacroAction action) throws InterruptedException {
return MacroExecutor.callOnClientThread(mc, () -> { return MacroClientThread.callOnClientThread(mc, () -> {
if (action instanceof OpenContainerAction open) return open.canExecuteNow(mc); if (action instanceof OpenContainerAction open) return open.canExecuteNow(mc);
if (action instanceof InteractEntityAction interact) return interact.canExecuteNow(mc); if (action instanceof InteractEntityAction interact) return interact.canExecuteNow(mc);
return true; return true;
@ -103,7 +103,7 @@ final class MacroActionRunner {
} }
private static boolean runTargetInteractionAttempt(Minecraft mc, MacroAction action) throws InterruptedException { private static boolean runTargetInteractionAttempt(Minecraft mc, MacroAction action) throws InterruptedException {
return MacroExecutor.callOnClientThread(mc, () -> { return MacroClientThread.callOnClientThread(mc, () -> {
try { try {
if (action instanceof OpenContainerAction open) return open.tryExecute(mc); if (action instanceof OpenContainerAction open) return open.tryExecute(mc);
if (action instanceof InteractEntityAction interact) return interact.tryExecute(mc); if (action instanceof InteractEntityAction interact) return interact.tryExecute(mc);
@ -173,7 +173,7 @@ final class MacroActionRunner {
long deadline = System.nanoTime() + 500_000_000L; long deadline = System.nanoTime() + 500_000_000L;
while (MacroExecutor.isCurrentRunActive()) { while (MacroExecutor.isCurrentRunActive()) {
Boolean ready = MacroExecutor.callOnClientThread(mc, () -> { Boolean ready = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null || mc.gui.screen() == null) return false; if (mc.player == null || mc.gui.screen() == null) return false;
if (mc.player.containerMenu != null && mc.player.containerMenu != mc.player.inventoryMenu) { if (mc.player.containerMenu != null && mc.player.containerMenu != mc.player.inventoryMenu) {
return mc.player.containerMenu.getStateId() > 0; return mc.player.containerMenu.getStateId() > 0;
@ -197,8 +197,8 @@ final class MacroActionRunner {
+ (t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage())); + (t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage()));
} }
}; };
if (usesTickAlignedDispatch(action)) MacroExecutor.runOnClientTick(mc, body); if (usesTickAlignedDispatch(action)) MacroClientThread.runOnClientTick(mc, body);
else MacroExecutor.runOnClientThread(mc, body); else MacroClientThread.runOnClientThread(mc, body);
} }
public static boolean usesTickAlignedDispatch(MacroAction action) { public static boolean usesTickAlignedDispatch(MacroAction action) {
@ -207,7 +207,7 @@ final class MacroActionRunner {
public static void runItemActionPaced(Minecraft mc, ItemAction ia) throws InterruptedException { public static void runItemActionPaced(Minecraft mc, ItemAction ia) throws InterruptedException {
MacroExecutor.setCurrentStatus(ia.getDisplayName()); MacroExecutor.setCurrentStatus(ia.getDisplayName());
java.util.List<Runnable> plan = MacroExecutor.callOnClientThread(mc, () -> ia.buildClickPlan(mc), java.util.Collections.<Runnable>emptyList()); java.util.List<Runnable> plan = MacroClientThread.callOnClientThread(mc, () -> ia.buildClickPlan(mc), java.util.Collections.<Runnable>emptyList());
if (plan == null || plan.isEmpty()) return; if (plan == null || plan.isEmpty()) return;
long delayMs = Math.max(0, ia.clickDelayMs); long delayMs = Math.max(0, ia.clickDelayMs);
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get(); MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
@ -264,7 +264,7 @@ final class MacroActionRunner {
try { r.run(); } try { r.run(); }
catch (Throwable t) { AutismClientMessaging.sendPrefixed("\u00a7cAddon action (client task) error: " + (t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage())); } catch (Throwable t) { AutismClientMessaging.sendPrefixed("\u00a7cAddon action (client task) error: " + (t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage())); }
}); });
try { MacroExecutor.runOnClientThread(Minecraft.getInstance(), safe); } try { MacroClientThread.runOnClientThread(Minecraft.getInstance(), safe); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
} }
@ -278,7 +278,7 @@ final class MacroActionRunner {
}); });
return value.get(); return value.get();
}; };
try { return MacroExecutor.callOnClientThread(Minecraft.getInstance(), safe, null); } try { return MacroClientThread.callOnClientThread(Minecraft.getInstance(), safe, null); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; }
} }
@ -335,14 +335,14 @@ final class MacroActionRunner {
int times = action.repeatTimes(); int times = action.repeatTimes();
for (int i = 0; i < times && MacroExecutor.isCurrentRunActive(); i++) { for (int i = 0; i < times && MacroExecutor.isCurrentRunActive(); i++) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { action.sendUsePacket(mc); } try { action.sendUsePacket(mc); }
catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use phase: " + e.getMessage()); } catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use phase: " + e.getMessage()); }
}); });
final boolean[] gateInstalled = { false }; final boolean[] gateInstalled = { false };
if (action.shouldGate()) { if (action.shouldGate()) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { gateInstalled[0] = action.installGate(mc); } try { gateInstalled[0] = action.installGate(mc); }
catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use gate: " + e.getMessage()); } catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use gate: " + e.getMessage()); }
}); });
@ -359,13 +359,13 @@ final class MacroActionRunner {
if (wasOnThread) { if (wasOnThread) {
action.removeGate(); action.removeGate();
} else { } else {
MacroExecutor.runOnClientThread(mc, action::removeGate); MacroClientThread.runOnClientThread(mc, action::removeGate);
} }
} }
} }
if (!MacroExecutor.isCurrentRunActive()) break; if (!MacroExecutor.isCurrentRunActive()) break;
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { action.finishRelease(mc); } try { action.finishRelease(mc); }
catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use release: " + e.getMessage()); } catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in Use release: " + e.getMessage()); }
}); });
@ -375,7 +375,7 @@ final class MacroActionRunner {
public static void runClickActionBurst(Minecraft mc, ClickAction action) throws InterruptedException { public static void runClickActionBurst(Minecraft mc, ClickAction action) throws InterruptedException {
int times = Math.max(1, action.clickCount); int times = Math.max(1, action.clickCount);
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
for (int c = 0; c < times && MacroExecutor.isCurrentRunActive(); c++) { for (int c = 0; c < times && MacroExecutor.isCurrentRunActive(); c++) {
try { try {
action.execute(mc); action.execute(mc);
@ -402,18 +402,18 @@ final class MacroActionRunner {
if (action == null) return; if (action == null) return;
int delayTicks = StoreItemAction.clampDelayTicks(action.delayTicks); int delayTicks = StoreItemAction.clampDelayTicks(action.delayTicks);
if (delayTicks <= 0) { if (delayTicks <= 0) {
MacroExecutor.runOnClientThread(mc, () -> action.doTransfer(mc)); MacroClientThread.runOnClientThread(mc, () -> action.doTransfer(mc));
return; return;
} }
List<Integer> slots = MacroExecutor.callOnClientThread(mc, () -> action.collectTransferSlots(mc), List.of()); List<Integer> slots = MacroClientThread.callOnClientThread(mc, () -> action.collectTransferSlots(mc), List.of());
for (int i = 0; i < slots.size() && MacroExecutor.isCurrentRunActive(); i++) { for (int i = 0; i < slots.size() && MacroExecutor.isCurrentRunActive(); i++) {
AutismInventoryClickHelper.click(mc, slots.get(i), 0, net.minecraft.world.inventory.ContainerInput.QUICK_MOVE); AutismInventoryClickHelper.click(mc, slots.get(i), 0, net.minecraft.world.inventory.ContainerInput.QUICK_MOVE);
if (i + 1 < slots.size()) waitTicks(delayTicks); if (i + 1 < slots.size()) waitTicks(delayTicks);
} }
if (action.closeAfter && !action.persistent) { if (action.closeAfter && !action.persistent) {
MacroExecutor.runOnClientThread(mc, () -> AutismGuiActions.closeCurrentScreen(mc, action.closeSendPkt, false)); MacroClientThread.runOnClientThread(mc, () -> AutismGuiActions.closeCurrentScreen(mc, action.closeSendPkt, false));
} }
} }
@ -430,7 +430,7 @@ final class MacroActionRunner {
boolean sneaking = action.sneak; boolean sneaking = action.sneak;
try { try {
if (action.useMode == UseItemAction.UseMode.CUSTOM_HOLD) { if (action.useMode == UseItemAction.UseMode.CUSTOM_HOLD) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
if (sneaking) autismclient.util.AutismMacroSneak.forceSneak(mc, true); if (sneaking) autismclient.util.AutismMacroSneak.forceSneak(mc, true);
action.execute(mc); action.execute(mc);
@ -440,7 +440,7 @@ final class MacroActionRunner {
if (action.holdTicks > 0) { if (action.holdTicks > 0) {
waitTicks(action.holdTicks); waitTicks(action.holdTicks);
if (!MacroExecutor.isCurrentRunActive()) return; if (!MacroExecutor.isCurrentRunActive()) return;
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { action.sendRelease(mc); } try { action.sendRelease(mc); }
catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in UseItem release: " + e.getMessage()); } catch (Exception e) { AutismClientMessaging.sendPrefixed("\u00a7cError in UseItem release: " + e.getMessage()); }
}, action.isTickAligned()); }, action.isTickAligned());
@ -451,7 +451,7 @@ final class MacroActionRunner {
int times = Math.max(1, action.useCount); int times = Math.max(1, action.useCount);
for (int i = 0; i < times && MacroExecutor.isCurrentRunActive(); i++) { for (int i = 0; i < times && MacroExecutor.isCurrentRunActive(); i++) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
if (sneaking) autismclient.util.AutismMacroSneak.forceSneak(mc, true); if (sneaking) autismclient.util.AutismMacroSneak.forceSneak(mc, true);
action.execute(mc); action.execute(mc);
@ -476,7 +476,7 @@ final class MacroActionRunner {
for (int repeat = 0; repeat < repeats && MacroExecutor.isCurrentRunActive(); repeat++) { for (int repeat = 0; repeat < repeats && MacroExecutor.isCurrentRunActive(); repeat++) {
for (int slot : slots) { for (int slot : slots) {
if (!MacroExecutor.isCurrentRunActive()) return; if (!MacroExecutor.isCurrentRunActive()) return;
MacroExecutor.runOnClientThread(mc, () -> action.executeClick(mc, slot)); MacroClientThread.runOnClientThread(mc, () -> action.executeClick(mc, slot));
sent++; sent++;
if (delay > 0 && sent < total) waitTicks(delay); if (delay > 0 && sent < total) waitTicks(delay);
} }
@ -497,19 +497,19 @@ final class MacroActionRunner {
private static void waitForUseItemFinish(Minecraft mc, int fallbackTicks) throws InterruptedException { private static void waitForUseItemFinish(Minecraft mc, int fallbackTicks) throws InterruptedException {
if (mc == null || !MacroExecutor.isCurrentRunActive()) return; if (mc == null || !MacroExecutor.isCurrentRunActive()) return;
if (!Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, if (!Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc,
() -> mc.player != null && mc.player.isUsingItem(), () -> mc.player != null && mc.player.isUsingItem(),
Boolean.FALSE))) { Boolean.FALSE))) {
return; return;
} }
int remaining = MacroExecutor.callOnClientThread(mc, int remaining = MacroClientThread.callOnClientThread(mc,
() -> mc.player == null ? 0 : Math.max(0, mc.player.getUseItemRemainingTicks()), () -> mc.player == null ? 0 : Math.max(0, mc.player.getUseItemRemainingTicks()),
0); 0);
int maxTicks = Math.max(8, remaining > 0 ? remaining + 8 : fallbackTicks + 8); int maxTicks = Math.max(8, remaining > 0 ? remaining + 8 : fallbackTicks + 8);
maxTicks = Math.min(maxTicks, 72000); maxTicks = Math.min(maxTicks, 72000);
for (int i = 0; i < maxTicks && MacroExecutor.isCurrentRunActive(); i++) { for (int i = 0; i < maxTicks && MacroExecutor.isCurrentRunActive(); i++) {
if (!Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, if (!Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc,
() -> mc.player != null && mc.player.isUsingItem(), () -> mc.player != null && mc.player.isUsingItem(),
Boolean.FALSE))) { Boolean.FALSE))) {
return; return;

View file

@ -46,7 +46,7 @@ final class MacroBreak {
if (sneakTick != lastSneakTick) { if (sneakTick != lastSneakTick) {
lastSneakTick = sneakTick; lastSneakTick = sneakTick;
final String sneakMode = action.sneakMode; final String sneakMode = action.sneakMode;
MacroExecutor.runOnClientThread(mc, () -> holdMacroSneak(mc, sneakMode), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> holdMacroSneak(mc, sneakMode), action.isTickAligned());
} }
} }
@ -73,17 +73,17 @@ final class MacroBreak {
long ns = t == InteractTiming.CUSTOM long ns = t == InteractTiming.CUSTOM
? Math.abs((long) action.interactCustomMs) * 1_000_000L : 0L; ? Math.abs((long) action.interactCustomMs) * 1_000_000L : 0L;
if (interactFirst) { if (interactFirst) {
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned()); sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
} else if (t == InteractTiming.AFTER_PLUS) { } else if (t == InteractTiming.AFTER_PLUS) {
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned()); sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
} else { } else {
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned()); sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
} }
} else { } else {
sendInstaBreakAttempt(mc, target, direction, action.isTickAligned()); sendInstaBreakAttempt(mc, target, direction, action.isTickAligned());
@ -100,7 +100,7 @@ final class MacroBreak {
if (action.sneak) { if (action.sneak) {
final String sneakMode = action.sneakMode; final String sneakMode = action.sneakMode;
try { try {
MacroExecutor.runOnClientThread(mc, () -> releaseMacroSneak(mc, sneakMode)); MacroClientThread.runOnClientThread(mc, () -> releaseMacroSneak(mc, sneakMode));
} catch (InterruptedException interrupted) { } catch (InterruptedException interrupted) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
@ -122,7 +122,7 @@ final class MacroBreak {
private static boolean ensureInstaBreakPickaxe(Minecraft mc, InstaBreakAction action) throws InterruptedException { private static boolean ensureInstaBreakPickaxe(Minecraft mc, InstaBreakAction action) throws InterruptedException {
return MacroExecutor.callOnClientThread(mc, () -> { return MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null) return false; if (mc.player == null) return false;
if (mc.player.getMainHandItem().is(ItemTags.PICKAXES)) return true; if (mc.player.getMainHandItem().is(ItemTags.PICKAXES)) return true;
if (!action.autoPickaxe) return false; if (!action.autoPickaxe) return false;
@ -148,7 +148,7 @@ final class MacroBreak {
} }
private static void sendInstaBreakAttempt(Minecraft mc, BlockPos pos, Direction direction, boolean tickAligned) throws InterruptedException { private static void sendInstaBreakAttempt(Minecraft mc, BlockPos pos, Direction direction, boolean tickAligned) throws InterruptedException {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null || mc.level == null || mc.gameMode == null || mc.getConnection() == null) return; if (mc.player == null || mc.level == null || mc.gameMode == null || mc.getConnection() == null) return;
BlockPos blockPos = pos.immutable(); BlockPos blockPos = pos.immutable();
Direction dir = direction == null ? Direction.UP : direction; Direction dir = direction == null ? Direction.UP : direction;
@ -203,7 +203,7 @@ final class MacroBreak {
if (!started[0]) { if (!started[0]) {
result = useNextSteps result = useNextSteps
? startBreakWithNextSteps(mc, action, target, direction, started, nextStepsFired, missingNextStepsWarned) ? startBreakWithNextSteps(mc, action, target, direction, started, nextStepsFired, missingNextStepsWarned)
: MacroExecutor.callOnClientThread(mc, () -> startBreakOnClient(mc, action, target, direction, started), -1, action.isTickAligned()); : MacroClientThread.callOnClientThread(mc, () -> startBreakOnClient(mc, action, target, direction, started), -1, action.isTickAligned());
} else if (action.interact && action.interactTiming == InteractTiming.CUSTOM) { } else if (action.interact && action.interactTiming == InteractTiming.CUSTOM) {
result = useNextSteps result = useNextSteps
? breakCustomTickWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned) ? breakCustomTickWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
@ -211,7 +211,7 @@ final class MacroBreak {
} else { } else {
result = useNextSteps result = useNextSteps
? breakContinueWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned) ? breakContinueWithNextSteps(mc, action, target, direction, nextStepsFired, missingNextStepsWarned)
: MacroExecutor.callOnClientThread(mc, () -> breakContinueOnClient(mc, action, target, direction), -1, action.isTickAligned()); : MacroClientThread.callOnClientThread(mc, () -> breakContinueOnClient(mc, action, target, direction), -1, action.isTickAligned());
} }
if (result < 0) { if (result < 0) {
@ -222,7 +222,7 @@ final class MacroBreak {
runBreakNextStepsAfterCompletion(mc, action, nextStepsFired, missingNextStepsWarned); runBreakNextStepsAfterCompletion(mc, action, nextStepsFired, missingNextStepsWarned);
} else if (action.interact && action.interactTiming == InteractTiming.AFTER_PLUS) { } else if (action.interact && action.interactTiming == InteractTiming.AFTER_PLUS) {
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, target, direction), action.isTickAligned());
} }
completed++; completed++;
MacroExecutor.setCurrentStatus("Break " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes)); MacroExecutor.setCurrentStatus("Break " + completed + "/" + (targetTimes == 0 ? "\u221e" : targetTimes));
@ -237,7 +237,7 @@ final class MacroBreak {
} }
} finally { } finally {
final boolean wasMining = started[0]; final boolean wasMining = started[0];
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (wasMining && mc.gameMode != null && mc.gameMode.isDestroying()) mc.gameMode.stopDestroyBlock(); if (wasMining && mc.gameMode != null && mc.gameMode.isDestroying()) mc.gameMode.stopDestroyBlock();
if (action.sneak) releaseMacroSneak(mc, action.sneakMode); if (action.sneak) releaseMacroSneak(mc, action.sneakMode);
}, action.isTickAligned()); }, action.isTickAligned());
@ -248,7 +248,7 @@ final class MacroBreak {
private static int startBreakWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, private static int startBreakWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
boolean[] started, boolean[] nextStepsFired, boolean[] started, boolean[] nextStepsFired,
boolean[] missingNextStepsWarned) throws InterruptedException { boolean[] missingNextStepsWarned) throws InterruptedException {
MacroExecutor.BreakStartPlan plan = MacroExecutor.callOnClientThread(mc, () -> prepareBreakStartOnClient(mc, action, pos), new MacroExecutor.BreakStartPlan(-1, false, false)); MacroExecutor.BreakStartPlan plan = MacroClientThread.callOnClientThread(mc, () -> prepareBreakStartOnClient(mc, action, pos), new MacroExecutor.BreakStartPlan(-1, false, false));
if (plan.result() != 0) return plan.result(); if (plan.result() != 0) return plan.result();
if (plan.instant() && plan.interactFirst()) { if (plan.instant() && plan.interactFirst()) {
@ -256,7 +256,7 @@ final class MacroBreak {
if (!MacroExecutor.isCurrentRunActive()) return -1; if (!MacroExecutor.isCurrentRunActive()) return -1;
} }
int result = MacroExecutor.callOnClientThread(mc, () -> startPreparedBreakOnClient(mc, action, pos, dir, started), -1, action.isTickAligned()); int result = MacroClientThread.callOnClientThread(mc, () -> startPreparedBreakOnClient(mc, action, pos, dir, started), -1, action.isTickAligned());
return result; return result;
} }
@ -320,7 +320,7 @@ final class MacroBreak {
private static int breakContinueWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, private static int breakContinueWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
boolean[] nextStepsFired, boolean[] nextStepsFired,
boolean[] missingNextStepsWarned) throws InterruptedException { boolean[] missingNextStepsWarned) throws InterruptedException {
MacroExecutor.BreakContinuePlan plan = MacroExecutor.callOnClientThread(mc, () -> inspectBreakContinueOnClient(mc, action, pos), new MacroExecutor.BreakContinuePlan(-1, false, false)); MacroExecutor.BreakContinuePlan plan = MacroClientThread.callOnClientThread(mc, () -> inspectBreakContinueOnClient(mc, action, pos), new MacroExecutor.BreakContinuePlan(-1, false, false));
if (plan.result() != 0) return plan.result(); if (plan.result() != 0) return plan.result();
InteractTiming timing = action.interactTiming; InteractTiming timing = action.interactTiming;
@ -333,7 +333,7 @@ final class MacroBreak {
if (!MacroExecutor.isCurrentRunActive()) return -1; if (!MacroExecutor.isCurrentRunActive()) return -1;
} }
int result = MacroExecutor.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned()); int result = MacroClientThread.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
return result; return result;
} }
@ -381,7 +381,7 @@ final class MacroBreak {
private static int breakCustomTickWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir, private static int breakCustomTickWithNextSteps(Minecraft mc, BreakAction action, BlockPos pos, Direction dir,
boolean[] nextStepsFired, boolean[] nextStepsFired,
boolean[] missingNextStepsWarned) throws InterruptedException { boolean[] missingNextStepsWarned) throws InterruptedException {
boolean willBreak = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { boolean willBreak = Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
if (mc.level == null || mc.player == null) return Boolean.FALSE; if (mc.level == null || mc.player == null) return Boolean.FALSE;
BlockState state = mc.level.getBlockState(pos); BlockState state = mc.level.getBlockState(pos);
if (state.isAir()) return Boolean.FALSE; if (state.isAir()) return Boolean.FALSE;
@ -389,7 +389,7 @@ final class MacroBreak {
}, Boolean.FALSE)); }, Boolean.FALSE));
if (!willBreak) { if (!willBreak) {
return MacroExecutor.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned()); return MacroClientThread.callOnClientThread(mc, () -> continueBreakOnClient(mc, action, pos, dir), -1, action.isTickAligned());
} }
long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L; long ns = Math.abs((long) action.interactCustomMs) * 1_000_000L;
@ -398,15 +398,15 @@ final class MacroBreak {
runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned); runBreakNextStepsOnce(mc, action, nextStepsFired, missingNextStepsWarned);
if (!MacroExecutor.isCurrentRunActive()) return -1; if (!MacroExecutor.isCurrentRunActive()) return -1;
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned()); broke = MacroClientThread.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
} else { } else {
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned()); broke = MacroClientThread.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
} }
return broke; return broke;
} }
private static int breakCustomTick(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) throws InterruptedException { private static int breakCustomTick(Minecraft mc, BreakAction action, BlockPos pos, Direction dir) throws InterruptedException {
boolean willBreak = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { boolean willBreak = Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
if (mc.level == null || mc.player == null) return Boolean.FALSE; if (mc.level == null || mc.player == null) return Boolean.FALSE;
BlockState s = mc.level.getBlockState(pos); BlockState s = mc.level.getBlockState(pos);
if (s.isAir()) return Boolean.FALSE; if (s.isAir()) return Boolean.FALSE;
@ -415,7 +415,7 @@ final class MacroBreak {
if (!willBreak) { if (!willBreak) {
return MacroExecutor.callOnClientThread(mc, () -> { return MacroClientThread.callOnClientThread(mc, () -> {
if (mc.level == null || mc.gameMode == null || mc.player == null) return -1; if (mc.level == null || mc.gameMode == null || mc.player == null) return -1;
if (mc.level.getBlockState(pos).isAir()) return 1; if (mc.level.getBlockState(pos).isAir()) return 1;
if (action.sneak) holdMacroSneak(mc, action.sneakMode); if (action.sneak) holdMacroSneak(mc, action.sneakMode);
@ -429,14 +429,14 @@ final class MacroBreak {
int broke; int broke;
if (action.interactCustomMs < 0) { if (action.interactCustomMs < 0) {
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned()); broke = MacroClientThread.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
} else { } else {
broke = MacroExecutor.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned()); broke = MacroClientThread.callOnClientThread(mc, () -> breakAndDetectOnClient(mc, pos, dir), -1, action.isTickAligned());
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
MacroExecutor.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> sendBlockInteract(mc, pos, dir), action.isTickAligned());
} }
return broke; return broke;
} }

View file

@ -340,7 +340,7 @@ final class MacroCaptureAutofill {
while (MacroExecutor.isCurrentRunActive()) { while (MacroExecutor.isCurrentRunActive()) {
CaptureValueAction.Preview preview; CaptureValueAction.Preview preview;
try { try {
preview = MacroExecutor.callOnClientThread(mc, () -> action.previewCurrent(mc), preview = MacroClientThread.callOnClientThread(mc, () -> action.previewCurrent(mc),
CaptureValueAction.Preview.unavailable("Not available")); CaptureValueAction.Preview.unavailable("Not available"));
} catch (InterruptedException interrupted) { } catch (InterruptedException interrupted) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -374,7 +374,7 @@ final class MacroCaptureAutofill {
String keySnapshot = trackedKey; String keySnapshot = trackedKey;
int rowSnapshot = trackedRow; int rowSnapshot = trackedRow;
String objectiveSnapshot = trackedObjective; String objectiveSnapshot = trackedObjective;
line = MacroExecutor.callOnClientThread(mc, line = MacroClientThread.callOnClientThread(mc,
() -> action.resolveScoreboardLine(mc, keySnapshot, rowSnapshot, objectiveSnapshot), null); () -> action.resolveScoreboardLine(mc, keySnapshot, rowSnapshot, objectiveSnapshot), null);
} catch (InterruptedException interrupted) { } catch (InterruptedException interrupted) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();

View file

@ -0,0 +1,155 @@
package autismclient.util.macro;
import autismclient.AutismClientAddon;
import autismclient.modules.PackHideState;
import net.minecraft.client.Minecraft;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
final class MacroClientThread {
private MacroClientThread() {
}
static void runOnClientThread(Minecraft mc, Runnable runnable) throws InterruptedException {
if (PackHideState.isHardLocked()) return;
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
Runnable contextual = () -> MacroExecutor.withRunContext(scheduledRun, runnable);
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return;
contextual.run();
return;
}
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
mc.execute(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
contextual.run();
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
}
static void runOnClientThread(Minecraft mc, Runnable runnable, boolean tickAligned) throws InterruptedException {
if (tickAligned) runOnClientTick(mc, runnable);
else runOnClientThread(mc, runnable);
}
public static void postOnClientThread(Minecraft mc, Runnable runnable, boolean tickAligned) throws InterruptedException {
if (tickAligned) {
runOnClientTick(mc, runnable);
return;
}
if (PackHideState.isHardLocked()) return;
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
mc.execute(() -> {
if (PackHideState.isHardLocked()) return;
MacroExecutor.withRunContext(scheduledRun, runnable);
});
}
static void runOnClientTick(Minecraft mc, Runnable runnable) throws InterruptedException {
if (PackHideState.isHardLocked()) return;
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
Runnable contextual = () -> MacroExecutor.withRunContext(scheduledRun, runnable);
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return;
contextual.run();
return;
}
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
TICK_ALIGNED.add(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
contextual.run();
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
}
static final java.util.concurrent.ConcurrentLinkedQueue<Runnable> TICK_ALIGNED =
new java.util.concurrent.ConcurrentLinkedQueue<>();
public static void drainTickAligned() {
if (autismclient.modules.AutoTotemModule.operationActive()) return;
Runnable task;
while ((task = TICK_ALIGNED.poll()) != null) {
try {
task.run();
} catch (Throwable t) {
AutismClientAddon.LOG.debug("[Autism] Tick-aligned macro task failed", t);
}
}
}
static <T> T callOnClientThread(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback) throws InterruptedException {
if (PackHideState.isHardLocked()) return fallback;
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
java.util.function.Supplier<T> contextual = () -> {
AtomicReference<T> value = new AtomicReference<>(fallback);
MacroExecutor.withRunContext(scheduledRun, () -> value.set(supplier.get()));
return value.get();
};
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return fallback;
return contextual.get();
}
AtomicReference<T> result = new AtomicReference<>(fallback);
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
mc.execute(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
result.set(contextual.get());
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
return result.get();
}
static <T> T callOnClientThread(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback,
boolean tickAligned) throws InterruptedException {
return tickAligned ? callOnClientTick(mc, supplier, fallback) : callOnClientThread(mc, supplier, fallback);
}
private static <T> T callOnClientTick(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback) throws InterruptedException {
if (PackHideState.isHardLocked()) return fallback;
MacroExecutor.RunState scheduledRun = MacroExecutor.CURRENT_RUN.get();
java.util.function.Supplier<T> contextual = () -> {
AtomicReference<T> value = new AtomicReference<>(fallback);
MacroExecutor.withRunContext(scheduledRun, () -> value.set(supplier.get()));
return value.get();
};
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return fallback;
return contextual.get();
}
AtomicReference<T> result = new AtomicReference<>(fallback);
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
TICK_ALIGNED.add(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
result.set(contextual.get());
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
return result.get();
}
}

View file

@ -16,7 +16,7 @@ final class MacroDurability {
AtomicReference<DurabilityUseNextSession> sessionRef = new AtomicReference<>(); AtomicReference<DurabilityUseNextSession> sessionRef = new AtomicReference<>();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
while (MacroExecutor.isCurrentRunActive()) { while (MacroExecutor.isCurrentRunActive()) {
if (Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> tickDurabilityUseNext(mc, action, sessionRef), Boolean.FALSE))) { if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> tickDurabilityUseNext(mc, action, sessionRef), Boolean.FALSE))) {
return; return;
} }
if (action.timeoutMs > 0 && System.currentTimeMillis() - start >= action.timeoutMs) return; if (action.timeoutMs > 0 && System.currentTimeMillis() - start >= action.timeoutMs) return;

View file

@ -1300,8 +1300,8 @@ public class MacroExecutor {
} else if (!sna.sneak) { } else if (!sna.sneak) {
currentPersistentActions().removeIf(p -> p instanceof SneakAction); currentPersistentActions().removeIf(p -> p instanceof SneakAction);
} }
if (sna.persistent || !sna.sneak) postOnClientThread(mc, () -> applyAggregateSneakState(mc), sna.isTickAligned()); if (sna.persistent || !sna.sneak) MacroClientThread.postOnClientThread(mc, () -> applyAggregateSneakState(mc), sna.isTickAligned());
else postOnClientThread(mc, () -> sna.execute(mc), sna.isTickAligned()); else MacroClientThread.postOnClientThread(mc, () -> sna.execute(mc), sna.isTickAligned());
} }
else if (action instanceof SprintAction) { else if (action instanceof SprintAction) {
SprintAction spa = (SprintAction) action; SprintAction spa = (SprintAction) action;
@ -1311,8 +1311,8 @@ public class MacroExecutor {
} else if (!spa.sprint) { } else if (!spa.sprint) {
currentPersistentActions().removeIf(p -> p instanceof SprintAction); currentPersistentActions().removeIf(p -> p instanceof SprintAction);
} }
if (spa.persistent || !spa.sprint) postOnClientThread(mc, () -> applyAggregateSprintState(mc), spa.isTickAligned()); if (spa.persistent || !spa.sprint) MacroClientThread.postOnClientThread(mc, () -> applyAggregateSprintState(mc), spa.isTickAligned());
else postOnClientThread(mc, () -> spa.execute(mc), spa.isTickAligned()); else MacroClientThread.postOnClientThread(mc, () -> spa.execute(mc), spa.isTickAligned());
} }
else if (action instanceof DisconnectAction) { else if (action instanceof DisconnectAction) {
DisconnectAction da2 = (DisconnectAction) action; DisconnectAction da2 = (DisconnectAction) action;
@ -1754,7 +1754,7 @@ public class MacroExecutor {
AutismClientMessaging.sendPrefixed("\u00a7cError in SendPacket: " + e.getMessage()); AutismClientMessaging.sendPrefixed("\u00a7cError in SendPacket: " + e.getMessage());
} }
} else { } else {
runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
action.execute(mc); action.execute(mc);
} catch (Exception e) { } catch (Exception e) {
@ -1807,7 +1807,7 @@ public class MacroExecutor {
case TAKE_OUT -> "XCarry Out"; case TAKE_OUT -> "XCarry Out";
case DROP -> "XCarry Drop"; case DROP -> "XCarry Drop";
}); });
runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
xsa.execute(mc); xsa.execute(mc);
} catch (Exception e) { } catch (Exception e) {
@ -1881,7 +1881,7 @@ public class MacroExecutor {
} }
if (isCurrentRunActive()) { if (isCurrentRunActive()) {
final PlaceAction fPlace = place; final PlaceAction fPlace = place;
postOnClientThread(mc, () -> { MacroClientThread.postOnClientThread(mc, () -> {
if (PackHideState.isHardLocked()) return; if (PackHideState.isHardLocked()) return;
try { try {
fPlace.execute(mc); fPlace.execute(mc);
@ -2038,7 +2038,7 @@ public class MacroExecutor {
private static void runPacedTpAction(Minecraft mc, PacedTpAction action) throws InterruptedException { private static void runPacedTpAction(Minecraft mc, PacedTpAction action) throws InterruptedException {
AtomicReference<autismclient.util.multi.PacketTeleportController.MacroHandle> handleRef = new AtomicReference<>(); AtomicReference<autismclient.util.multi.PacketTeleportController.MacroHandle> handleRef = new AtomicReference<>();
runOnClientThread(mc, () -> handleRef.set( MacroClientThread.runOnClientThread(mc, () -> handleRef.set(
autismclient.util.multi.PacketTeleportController.startMacro(action))); autismclient.util.multi.PacketTeleportController.startMacro(action)));
autismclient.util.multi.PacketTeleportController.MacroHandle handle = handleRef.get(); autismclient.util.multi.PacketTeleportController.MacroHandle handle = handleRef.get();
if (handle == null) return; if (handle == null) return;
@ -2386,8 +2386,8 @@ public class MacroExecutor {
} else if (!sna.sneak) { } else if (!sna.sneak) {
currentPersistentActions().removeIf(p -> p instanceof SneakAction); currentPersistentActions().removeIf(p -> p instanceof SneakAction);
} }
if (sna.persistent || !sna.sneak) postOnClientThread(mc, () -> applyAggregateSneakState(mc), sna.isTickAligned()); if (sna.persistent || !sna.sneak) MacroClientThread.postOnClientThread(mc, () -> applyAggregateSneakState(mc), sna.isTickAligned());
else postOnClientThread(mc, () -> sna.execute(mc), sna.isTickAligned()); else MacroClientThread.postOnClientThread(mc, () -> sna.execute(mc), sna.isTickAligned());
} else if (action instanceof SprintAction) { } else if (action instanceof SprintAction) {
SprintAction spa = (SprintAction) action; SprintAction spa = (SprintAction) action;
if (spa.persistent && spa.sprint) { if (spa.persistent && spa.sprint) {
@ -2396,8 +2396,8 @@ public class MacroExecutor {
} else if (!spa.sprint) { } else if (!spa.sprint) {
currentPersistentActions().removeIf(p -> p instanceof SprintAction); currentPersistentActions().removeIf(p -> p instanceof SprintAction);
} }
if (spa.persistent || !spa.sprint) postOnClientThread(mc, () -> applyAggregateSprintState(mc), spa.isTickAligned()); if (spa.persistent || !spa.sprint) MacroClientThread.postOnClientThread(mc, () -> applyAggregateSprintState(mc), spa.isTickAligned());
else postOnClientThread(mc, () -> spa.execute(mc), spa.isTickAligned()); else MacroClientThread.postOnClientThread(mc, () -> spa.execute(mc), spa.isTickAligned());
} else if (action instanceof NbtBookAction nba) { } else if (action instanceof NbtBookAction nba) {
int totalBooks = Math.max(1, nba.bookCount); int totalBooks = Math.max(1, nba.bookCount);
long delayMs = Math.max(1, nba.delayTicks) * 50L; long delayMs = Math.max(1, nba.delayTicks) * 50L;
@ -2473,7 +2473,7 @@ public class MacroExecutor {
case TAKE_OUT -> "XCarry Out"; case TAKE_OUT -> "XCarry Out";
case DROP -> "XCarry Drop"; case DROP -> "XCarry Drop";
}); });
runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
xsa.execute(mc); xsa.execute(mc);
} catch (Exception e) { } catch (Exception e) {
@ -2661,147 +2661,10 @@ public class MacroExecutor {
} }
static void runOnClientThread(Minecraft mc, Runnable runnable) throws InterruptedException {
if (PackHideState.isHardLocked()) return;
RunState scheduledRun = CURRENT_RUN.get();
Runnable contextual = () -> withRunContext(scheduledRun, runnable);
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return;
contextual.run();
return;
}
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
mc.execute(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
contextual.run();
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
}
static void runOnClientThread(Minecraft mc, Runnable runnable, boolean tickAligned) throws InterruptedException {
if (tickAligned) runOnClientTick(mc, runnable);
else runOnClientThread(mc, runnable);
}
private static void postOnClientThread(Minecraft mc, Runnable runnable, boolean tickAligned) throws InterruptedException {
if (tickAligned) {
runOnClientTick(mc, runnable);
return;
}
if (PackHideState.isHardLocked()) return;
RunState scheduledRun = CURRENT_RUN.get();
mc.execute(() -> {
if (PackHideState.isHardLocked()) return;
withRunContext(scheduledRun, runnable);
});
}
static void runOnClientTick(Minecraft mc, Runnable runnable) throws InterruptedException {
if (PackHideState.isHardLocked()) return;
RunState scheduledRun = CURRENT_RUN.get();
Runnable contextual = () -> withRunContext(scheduledRun, runnable);
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return;
contextual.run();
return;
}
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
TICK_ALIGNED.add(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
contextual.run();
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
}
private static final java.util.concurrent.ConcurrentLinkedQueue<Runnable> TICK_ALIGNED =
new java.util.concurrent.ConcurrentLinkedQueue<>();
public static void drainTickAligned() { public static void drainTickAligned() {
MacroClientThread.drainTickAligned();
if (autismclient.modules.AutoTotemModule.operationActive()) return;
Runnable task;
while ((task = TICK_ALIGNED.poll()) != null) {
try {
task.run();
} catch (Throwable t) {
AutismClientAddon.LOG.debug("[Autism] Tick-aligned macro task failed", t);
}
}
} }
static <T> T callOnClientThread(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback) throws InterruptedException {
if (PackHideState.isHardLocked()) return fallback;
RunState scheduledRun = CURRENT_RUN.get();
java.util.function.Supplier<T> contextual = () -> {
AtomicReference<T> value = new AtomicReference<>(fallback);
withRunContext(scheduledRun, () -> value.set(supplier.get()));
return value.get();
};
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return fallback;
return contextual.get();
}
AtomicReference<T> result = new AtomicReference<>(fallback);
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
mc.execute(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
result.set(contextual.get());
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
return result.get();
}
static <T> T callOnClientThread(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback,
boolean tickAligned) throws InterruptedException {
return tickAligned ? callOnClientTick(mc, supplier, fallback) : callOnClientThread(mc, supplier, fallback);
}
private static <T> T callOnClientTick(Minecraft mc, java.util.function.Supplier<T> supplier, T fallback) throws InterruptedException {
if (PackHideState.isHardLocked()) return fallback;
RunState scheduledRun = CURRENT_RUN.get();
java.util.function.Supplier<T> contextual = () -> {
AtomicReference<T> value = new AtomicReference<>(fallback);
withRunContext(scheduledRun, () -> value.set(supplier.get()));
return value.get();
};
if (mc.isSameThread()) {
if (PackHideState.isHardLocked()) return fallback;
return contextual.get();
}
AtomicReference<T> result = new AtomicReference<>(fallback);
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
AtomicBoolean pending = new AtomicBoolean(true);
TICK_ALIGNED.add(() -> {
try {
if (!pending.compareAndSet(true, false)) return;
if (PackHideState.isHardLocked()) return;
result.set(contextual.get());
} finally {
latch.countDown();
}
});
if (!latch.await(2000, TimeUnit.MILLISECONDS)) pending.set(false);
return result.get();
}
private static void runPlaceAction(Minecraft mc, PlaceAction action) throws InterruptedException { private static void runPlaceAction(Minecraft mc, PlaceAction action) throws InterruptedException {
if (mc == null || mc.player == null || mc.level == null) return; if (mc == null || mc.player == null || mc.level == null) return;
@ -2827,37 +2690,37 @@ public class MacroExecutor {
if (interactFirst) { if (interactFirst) {
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place"); MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
} else if (t == InteractTiming.WITH) { } else if (t == InteractTiming.WITH) {
runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { action.execute(mc); } catch (Exception e) { AutismClientAddon.LOG.debug("[Autism] Macro WITH-interact action failed", e); } try { action.execute(mc); } catch (Exception e) { AutismClientAddon.LOG.debug("[Autism] Macro WITH-interact action failed", e); }
MacroBreak.sendBlockInteract(mc, placePos, face); MacroBreak.sendBlockInteract(mc, placePos, face);
}, action.isTickAligned()); }, action.isTickAligned());
} else if (t == InteractTiming.AFTER_PLUS) { } else if (t == InteractTiming.AFTER_PLUS) {
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place"); MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
waitOneTick(); waitOneTick();
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
} else { } else {
MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place"); MacroActionRunner.runMacroActionOnClientThread(mc, action, "Place");
if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns); if (ns > 0) java.util.concurrent.locks.LockSupport.parkNanos(ns);
runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned()); MacroClientThread.runOnClientThread(mc, () -> MacroBreak.sendBlockInteract(mc, placePos, face), action.isTickAligned());
} }
} }
private static void waitForItemInSpecificHandlerSlot(Minecraft mc, int slotId, ItemTarget target) throws InterruptedException { private static void waitForItemInSpecificHandlerSlot(Minecraft mc, int slotId, ItemTarget target) throws InterruptedException {
while (isCurrentRunActive()) { while (isCurrentRunActive()) {
if (Boolean.TRUE.equals(callOnClientThread(mc, () -> handlerSlotMatchesItem(mc, slotId, target), Boolean.FALSE))) return; if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> handlerSlotMatchesItem(mc, slotId, target), Boolean.FALSE))) return;
waitOneTick(); waitOneTick();
} }
} }
private static void waitForAnyItemInSpecificHandlerSlot(Minecraft mc, int slotId) throws InterruptedException { private static void waitForAnyItemInSpecificHandlerSlot(Minecraft mc, int slotId) throws InterruptedException {
while (isCurrentRunActive()) { while (isCurrentRunActive()) {
if (Boolean.TRUE.equals(callOnClientThread(mc, () -> handlerSlotHasAnyItem(mc, slotId), Boolean.FALSE))) return; if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> handlerSlotHasAnyItem(mc, slotId), Boolean.FALSE))) return;
waitOneTick(); waitOneTick();
} }
} }
@ -3166,7 +3029,7 @@ public class MacroExecutor {
latch.countDown(); latch.countDown();
} }
}; };
if (tickAligned && !mc.isSameThread()) TICK_ALIGNED.add(task); if (tickAligned && !mc.isSameThread()) MacroClientThread.TICK_ALIGNED.add(task);
else mc.execute(task); else mc.execute(task);
latch.await(2, TimeUnit.SECONDS); latch.await(2, TimeUnit.SECONDS);
@ -3376,7 +3239,7 @@ public class MacroExecutor {
setCurrentStatus("Paying " + player + " " + amountLabel + " (" + (sent + 1) + "/" + targets.size() + ")"); setCurrentStatus("Paying " + player + " " + amountLabel + " (" + (sent + 1) + "/" + targets.size() + ")");
runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
try { try {
if (PackHideState.isHardLocked() || mc.getConnection() == null) return; if (PackHideState.isHardLocked() || mc.getConnection() == null) return;
if (commandToSend.startsWith("/") && commandToSend.length() > 1) { if (commandToSend.startsWith("/") && commandToSend.length() > 1) {

View file

@ -238,7 +238,7 @@ final class MacroPrearm {
if (!(action instanceof MacroCaptureOutput output)) return; if (!(action instanceof MacroCaptureOutput output)) return;
String name = MacroVariableContext.cleanRootName(output.getSaveAs()); String name = MacroVariableContext.cleanRootName(output.getSaveAs());
if (name.isEmpty()) return; if (name.isEmpty()) return;
MacroValue value = MacroExecutor.callOnClientThread(mc, () -> conditionOutputValue(action, mc), null); MacroValue value = MacroClientThread.callOnClientThread(mc, () -> conditionOutputValue(action, mc), null);
if (value != null) MacroVariables.setValue(name, value); if (value != null) MacroVariables.setValue(name, value);
} }

View file

@ -21,7 +21,7 @@ final class MacroXCarry {
if (xsa.requiresCursorStorage()) { if (xsa.requiresCursorStorage()) {
MacroExecutor.setCurrentStatus("XCarry Cursor"); MacroExecutor.setCurrentStatus("XCarry Cursor");
MacroExecutor.runOnClientThread(mc, () -> xsa.execute(mc)); MacroClientThread.runOnClientThread(mc, () -> xsa.execute(mc));
return; return;
} }
@ -34,7 +34,7 @@ final class MacroXCarry {
AtomicReference<List<Integer>> containerSlotIdsRef = new AtomicReference<>(List.of()); AtomicReference<List<Integer>> containerSlotIdsRef = new AtomicReference<>(List.of());
AtomicBoolean usingContainer = new AtomicBoolean(false); AtomicBoolean usingContainer = new AtomicBoolean(false);
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null) return; if (mc.player == null) return;
net.minecraft.world.inventory.AbstractContainerMenu current = mc.player.containerMenu; net.minecraft.world.inventory.AbstractContainerMenu current = mc.player.containerMenu;
if (current != null && current != mc.player.inventoryMenu) { if (current != null && current != mc.player.inventoryMenu) {
@ -47,7 +47,7 @@ final class MacroXCarry {
if (usingContainer.get() && containerTargetRef.get() == null) { if (usingContainer.get() && containerTargetRef.get() == null) {
AutismClientMessaging.sendPrefixed("XCarry click mode: missing container target, using fast mode."); AutismClientMessaging.sendPrefixed("XCarry click mode: missing container target, using fast mode.");
MacroExecutor.runOnClientThread(mc, () -> xsa.execute(mc)); MacroClientThread.runOnClientThread(mc, () -> xsa.execute(mc));
return; return;
} }
@ -55,7 +55,7 @@ final class MacroXCarry {
for (int slotId : containerSlotIdsRef.get()) { for (int slotId : containerSlotIdsRef.get()) {
if (!MacroExecutor.isCurrentRunActive()) return; if (!MacroExecutor.isCurrentRunActive()) return;
MacroExecutor.setCurrentStatus("XCarry Click: collect"); MacroExecutor.setCurrentStatus("XCarry Click: collect");
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null) return; if (mc.player == null || mc.gameMode == null) return;
net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get(); net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get();
if (handler == null || mc.player.containerMenu != handler) return; if (handler == null || mc.player.containerMenu != handler) return;
@ -66,7 +66,7 @@ final class MacroXCarry {
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null || mc.getConnection() == null) return; if (mc.player == null || mc.getConnection() == null) return;
net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get(); net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get();
if (handler == null) return; if (handler == null) return;
@ -74,7 +74,7 @@ final class MacroXCarry {
}); });
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player != null) { if (mc.player != null) {
mc.player.containerMenu = mc.player.inventoryMenu; mc.player.containerMenu = mc.player.inventoryMenu;
} }
@ -82,25 +82,25 @@ final class MacroXCarry {
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
MacroExecutor.runOnClientThread(mc, xsa::preparePutInStorageGuard); MacroClientThread.runOnClientThread(mc, xsa::preparePutInStorageGuard);
int xCarryAttempts = 0; int xCarryAttempts = 0;
while (MacroExecutor.isCurrentRunActive() && xCarryAttempts++ < 512) { while (MacroExecutor.isCurrentRunActive() && xCarryAttempts++ < 512) {
XCarryAction.PutInMove move = MacroExecutor.callOnClientThread(mc, () -> { XCarryAction.PutInMove move = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null) return null; if (mc.player == null) return null;
return xsa.findNextPutInMove(mc.player.inventoryMenu); return xsa.findNextPutInMove(mc.player.inventoryMenu);
}, null); }, null);
if (move == null) break; if (move == null) break;
MacroExecutor.setCurrentStatus("XCarry Click -> " + move.targetSlotId + " x" + move.count); MacroExecutor.setCurrentStatus("XCarry Click -> " + move.targetSlotId + " x" + move.count);
int targetBefore = MacroExecutor.callOnClientThread(mc, () -> { int targetBefore = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null) return 0; if (mc.player == null) return 0;
net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu; net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu;
if (move.targetSlotId < 0 || move.targetSlotId >= handler.slots.size()) return 0; if (move.targetSlotId < 0 || move.targetSlotId >= handler.slots.size()) return 0;
return handler.slots.get(move.targetSlotId).getItem().getCount(); return handler.slots.get(move.targetSlotId).getItem().getCount();
}, 0); }, 0);
boolean moved = MacroExecutor.callOnClientThread(mc, () -> { boolean moved = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null) return false; if (mc.player == null || mc.gameMode == null) return false;
net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu; net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu;
mc.player.containerMenu = handler; mc.player.containerMenu = handler;
@ -123,7 +123,7 @@ final class MacroXCarry {
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player != null) { if (mc.player != null) {
boolean active = XCarryAction.hasStoredItems(mc.player.inventoryMenu, xsa.carryCursor, xsa.activeStorageSlotIds()); boolean active = XCarryAction.hasStoredItems(mc.player.inventoryMenu, xsa.carryCursor, xsa.activeStorageSlotIds());
autismclient.util.AutismSharedState shared = autismclient.util.AutismSharedState.get(); autismclient.util.AutismSharedState shared = autismclient.util.AutismSharedState.get();
@ -136,7 +136,7 @@ final class MacroXCarry {
}); });
if (usingContainer.get()) { if (usingContainer.get()) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null) return; if (mc.player == null) return;
net.minecraft.world.inventory.AbstractContainerMenu containerHandler = containerHandlerRef.get(); net.minecraft.world.inventory.AbstractContainerMenu containerHandler = containerHandlerRef.get();
if (containerHandler != null) { if (containerHandler != null) {
@ -159,7 +159,7 @@ final class MacroXCarry {
if (xsa.requiresCursorStorage()) { if (xsa.requiresCursorStorage()) {
MacroExecutor.setCurrentStatus("XCarry Safe: Cursor"); MacroExecutor.setCurrentStatus("XCarry Safe: Cursor");
MacroExecutor.runOnClientThread(mc, () -> xsa.execute(mc)); MacroClientThread.runOnClientThread(mc, () -> xsa.execute(mc));
return; return;
} }
@ -172,7 +172,7 @@ final class MacroXCarry {
AtomicReference<List<Integer>> containerSlotIdsRef = new AtomicReference<>(List.of()); AtomicReference<List<Integer>> containerSlotIdsRef = new AtomicReference<>(List.of());
AtomicBoolean usingContainer = new AtomicBoolean(false); AtomicBoolean usingContainer = new AtomicBoolean(false);
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null) return; if (mc.player == null) return;
net.minecraft.world.inventory.AbstractContainerMenu current = mc.player.containerMenu; net.minecraft.world.inventory.AbstractContainerMenu current = mc.player.containerMenu;
if (current != null && current != mc.player.inventoryMenu) { if (current != null && current != mc.player.inventoryMenu) {
@ -185,7 +185,7 @@ final class MacroXCarry {
if (usingContainer.get() && containerTargetRef.get() == null) { if (usingContainer.get() && containerTargetRef.get() == null) {
AutismClientMessaging.sendPrefixed("XCarry safe mode: missing container target, using fast mode."); AutismClientMessaging.sendPrefixed("XCarry safe mode: missing container target, using fast mode.");
MacroExecutor.runOnClientThread(mc, () -> xsa.execute(mc)); MacroClientThread.runOnClientThread(mc, () -> xsa.execute(mc));
return; return;
} }
@ -196,7 +196,7 @@ final class MacroXCarry {
sendContainerClickThenTick(mc, containerHandlerRef.get(), slotId, 0, ContainerInput.QUICK_MOVE); sendContainerClickThenTick(mc, containerHandlerRef.get(), slotId, 0, ContainerInput.QUICK_MOVE);
} }
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null || mc.getConnection() == null) return; if (mc.player == null || mc.getConnection() == null) return;
net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get(); net.minecraft.world.inventory.AbstractContainerMenu handler = containerHandlerRef.get();
if (handler == null) return; if (handler == null) return;
@ -204,7 +204,7 @@ final class MacroXCarry {
}); });
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player != null) { if (mc.player != null) {
mc.player.containerMenu = mc.player.inventoryMenu; mc.player.containerMenu = mc.player.inventoryMenu;
} }
@ -212,14 +212,14 @@ final class MacroXCarry {
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
MacroExecutor.runOnClientThread(mc, xsa::preparePutInStorageGuard); MacroClientThread.runOnClientThread(mc, xsa::preparePutInStorageGuard);
int safeDelayTicks = XCarryAction.clampSafeClickDelayTicks(xsa.safeClickDelayTicks); int safeDelayTicks = XCarryAction.clampSafeClickDelayTicks(xsa.safeClickDelayTicks);
boolean delayAfterPickup = xsa.safeClickDelayAfterPickup; boolean delayAfterPickup = xsa.safeClickDelayAfterPickup;
boolean delayBeforeReturn = xsa.safeClickDelayBeforeReturn; boolean delayBeforeReturn = xsa.safeClickDelayBeforeReturn;
int attempts = 0; int attempts = 0;
while (MacroExecutor.isCurrentRunActive() && attempts++ < 512) { while (MacroExecutor.isCurrentRunActive() && attempts++ < 512) {
List<XCarryAction.PutInMove> group = MacroExecutor.callOnClientThread(mc, () -> nextXCarrySafeGroup(mc, xsa), List.of()); List<XCarryAction.PutInMove> group = MacroClientThread.callOnClientThread(mc, () -> nextXCarrySafeGroup(mc, xsa), List.of());
if (group.isEmpty()) break; if (group.isEmpty()) break;
XCarryAction.PutInMove first = group.get(0); XCarryAction.PutInMove first = group.get(0);
@ -233,7 +233,7 @@ final class MacroXCarry {
} }
} }
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player != null) { if (mc.player != null) {
boolean active = XCarryAction.hasStoredItems(mc.player.inventoryMenu, xsa.carryCursor, xsa.activeStorageSlotIds()); boolean active = XCarryAction.hasStoredItems(mc.player.inventoryMenu, xsa.carryCursor, xsa.activeStorageSlotIds());
autismclient.util.AutismSharedState shared = autismclient.util.AutismSharedState.get(); autismclient.util.AutismSharedState shared = autismclient.util.AutismSharedState.get();
@ -246,7 +246,7 @@ final class MacroXCarry {
}); });
if (usingContainer.get()) { if (usingContainer.get()) {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null) return; if (mc.player == null) return;
net.minecraft.world.inventory.AbstractContainerMenu containerHandler = containerHandlerRef.get(); net.minecraft.world.inventory.AbstractContainerMenu containerHandler = containerHandlerRef.get();
if (containerHandler != null) { if (containerHandler != null) {
@ -289,7 +289,7 @@ final class MacroXCarry {
private static boolean executeXCarrySafeGroup(Minecraft mc, List<XCarryAction.PutInMove> group, int delayTicks, private static boolean executeXCarrySafeGroup(Minecraft mc, List<XCarryAction.PutInMove> group, int delayTicks,
boolean delayAfterPickup, boolean delayBeforeReturn) throws InterruptedException { boolean delayAfterPickup, boolean delayBeforeReturn) throws InterruptedException {
if (mc == null || mc.player == null || mc.gameMode == null || group == null || group.isEmpty()) return false; if (mc == null || mc.player == null || mc.gameMode == null || group == null || group.isEmpty()) return false;
SafeGroupSnapshot snapshot = MacroExecutor.callOnClientThread(mc, () -> snapshotXCarrySafeGroup(mc, group), SafeGroupSnapshot.invalid()); SafeGroupSnapshot snapshot = MacroClientThread.callOnClientThread(mc, () -> snapshotXCarrySafeGroup(mc, group), SafeGroupSnapshot.invalid());
if (!snapshot.valid) return false; if (!snapshot.valid) return false;
SafeGroupSnapshot expected = executeXCarrySafeScript(mc, group, snapshot, delayTicks, delayAfterPickup, delayBeforeReturn); SafeGroupSnapshot expected = executeXCarrySafeScript(mc, group, snapshot, delayTicks, delayAfterPickup, delayBeforeReturn);
@ -305,7 +305,7 @@ final class MacroXCarry {
return SafeGroupSnapshot.invalid(); return SafeGroupSnapshot.invalid();
} }
XCarryAction.PutInMove first = group.get(0); XCarryAction.PutInMove first = group.get(0);
if (!Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { if (!Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return handler != null return handler != null
&& handler.getCarried().isEmpty() && handler.getCarried().isEmpty()
@ -314,7 +314,7 @@ final class MacroXCarry {
return SafeGroupSnapshot.invalid(); return SafeGroupSnapshot.invalid();
} }
SafeQuickCraftPlan quickCraftPlan = MacroExecutor.callOnClientThread(mc, () -> { SafeQuickCraftPlan quickCraftPlan = MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return createXCarryQuickCraftPlan(handler, group, snapshot); return createXCarryQuickCraftPlan(handler, group, snapshot);
}, SafeQuickCraftPlan.invalid()); }, SafeQuickCraftPlan.invalid());
@ -331,7 +331,7 @@ final class MacroXCarry {
return SafeGroupSnapshot.invalid(); return SafeGroupSnapshot.invalid();
} }
waitXCarrySafeAfterPickupDelay(delayTicks, true); waitXCarrySafeAfterPickupDelay(delayTicks, true);
if (!Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { if (!Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return xcarrySafeCarryingNow(handler, snapshot.sourceStack, snapshot.sourceCount); return xcarrySafeCarryingNow(handler, snapshot.sourceStack, snapshot.sourceCount);
}, Boolean.FALSE))) { }, Boolean.FALSE))) {
@ -409,7 +409,7 @@ final class MacroXCarry {
} }
} }
boolean hasLeftover = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { boolean hasLeftover = Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return handler != null && !handler.getCarried().isEmpty(); return handler != null && !handler.getCarried().isEmpty();
}, Boolean.FALSE)); }, Boolean.FALSE));
@ -417,12 +417,12 @@ final class MacroXCarry {
if (delayBeforeReturn) { if (delayBeforeReturn) {
waitXCarrySafeDelayTicks(delayTicks); waitXCarrySafeDelayTicks(delayTicks);
} }
int returnSlot = MacroExecutor.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, first.sourceSlotId()), -1); int returnSlot = MacroClientThread.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, first.sourceSlotId()), -1);
if (returnSlot < 0) return SafeGroupSnapshot.invalid(); if (returnSlot < 0) return SafeGroupSnapshot.invalid();
if (!sendXCarrySafeInventoryClick(mc, returnSlot, 0, ContainerInput.PICKUP)) return SafeGroupSnapshot.invalid(); if (!sendXCarrySafeInventoryClick(mc, returnSlot, 0, ContainerInput.PICKUP)) return SafeGroupSnapshot.invalid();
} }
boolean cursorEmpty = Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { boolean cursorEmpty = Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return handler != null && handler.getCarried().isEmpty(); return handler != null && handler.getCarried().isEmpty();
}, Boolean.FALSE)); }, Boolean.FALSE));
@ -433,7 +433,7 @@ final class MacroXCarry {
if (mc == null || count <= 0) return false; if (mc == null || count <= 0) return false;
int remaining = count; int remaining = count;
while (remaining > 0 && MacroExecutor.isCurrentRunActive()) { while (remaining > 0 && MacroExecutor.isCurrentRunActive()) {
int carriedCount = MacroExecutor.callOnClientThread(mc, () -> { int carriedCount = MacroClientThread.callOnClientThread(mc, () -> {
InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu; InventoryMenu handler = mc.player == null ? null : mc.player.inventoryMenu;
return handler == null ? 0 : handler.getCarried().getCount(); return handler == null ? 0 : handler.getCarried().getCount();
}, 0); }, 0);
@ -611,7 +611,7 @@ final class MacroXCarry {
private static boolean sendXCarrySafeInventoryClickBatch(Minecraft mc, SafeInventoryClick... clicks) throws InterruptedException { private static boolean sendXCarrySafeInventoryClickBatch(Minecraft mc, SafeInventoryClick... clicks) throws InterruptedException {
if (mc == null || clicks == null || clicks.length == 0) return false; if (mc == null || clicks == null || clicks.length == 0) return false;
return Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> { return Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null) return false; if (mc.player == null || mc.gameMode == null) return false;
InventoryMenu handler = mc.player.inventoryMenu; InventoryMenu handler = mc.player.inventoryMenu;
if (handler == null) return false; if (handler == null) return false;
@ -640,7 +640,7 @@ final class MacroXCarry {
private static boolean sendInventoryClickThenTick(Minecraft mc, int slotId, int button, ContainerInput input) throws InterruptedException { private static boolean sendInventoryClickThenTick(Minecraft mc, int slotId, int button, ContainerInput input) throws InterruptedException {
if (mc == null || mc.player == null || mc.gameMode == null) return false; if (mc == null || mc.player == null || mc.gameMode == null) return false;
boolean clicked = MacroExecutor.callOnClientThread(mc, () -> { boolean clicked = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null) return false; if (mc.player == null || mc.gameMode == null) return false;
InventoryMenu handler = mc.player.inventoryMenu; InventoryMenu handler = mc.player.inventoryMenu;
mc.player.containerMenu = handler; mc.player.containerMenu = handler;
@ -656,7 +656,7 @@ final class MacroXCarry {
private static boolean sendContainerClickThenTick(Minecraft mc, net.minecraft.world.inventory.AbstractContainerMenu handler, private static boolean sendContainerClickThenTick(Minecraft mc, net.minecraft.world.inventory.AbstractContainerMenu handler,
int slotId, int button, ContainerInput input) throws InterruptedException { int slotId, int button, ContainerInput input) throws InterruptedException {
if (mc == null || handler == null || input == null) return false; if (mc == null || handler == null || input == null) return false;
boolean clicked = MacroExecutor.callOnClientThread(mc, () -> { boolean clicked = MacroClientThread.callOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null || mc.player.containerMenu != handler) return false; if (mc.player == null || mc.gameMode == null || mc.player.containerMenu != handler) return false;
if (slotId < 0 || slotId >= handler.slots.size()) return false; if (slotId < 0 || slotId >= handler.slots.size()) return false;
if (handler.slots.get(slotId).getItem().isEmpty()) return false; if (handler.slots.get(slotId).getItem().isEmpty()) return false;
@ -671,10 +671,10 @@ final class MacroXCarry {
private static boolean waitForXCarrySafeLocal(Minecraft mc, int ticks, java.util.function.BooleanSupplier accepted) throws InterruptedException { private static boolean waitForXCarrySafeLocal(Minecraft mc, int ticks, java.util.function.BooleanSupplier accepted) throws InterruptedException {
int maxTicks = Math.max(1, ticks); int maxTicks = Math.max(1, ticks);
for (int i = 0; i < maxTicks && MacroExecutor.isCurrentRunActive(); i++) { for (int i = 0; i < maxTicks && MacroExecutor.isCurrentRunActive(); i++) {
if (Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> accepted != null && accepted.getAsBoolean(), Boolean.FALSE))) return true; if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> accepted != null && accepted.getAsBoolean(), Boolean.FALSE))) return true;
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
return Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> accepted != null && accepted.getAsBoolean(), Boolean.FALSE)); return Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> accepted != null && accepted.getAsBoolean(), Boolean.FALSE));
} }
private static void waitForXCarrySafeSettle(Minecraft mc, long startRevision, int minTicks, long maxMs) throws InterruptedException { private static void waitForXCarrySafeSettle(Minecraft mc, long startRevision, int minTicks, long maxMs) throws InterruptedException {
@ -693,9 +693,9 @@ final class MacroXCarry {
private static boolean waitForXCarrySafeFinalState(Minecraft mc, SafeGroupSnapshot snapshot, long startRevision) throws InterruptedException { private static boolean waitForXCarrySafeFinalState(Minecraft mc, SafeGroupSnapshot snapshot, long startRevision) throws InterruptedException {
waitForXCarrySafeSettle(mc, startRevision, 2, 250L); waitForXCarrySafeSettle(mc, startRevision, 2, 250L);
if (Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> xcarrySafeFinalMatches(mc, snapshot), Boolean.FALSE))) return true; if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> xcarrySafeFinalMatches(mc, snapshot), Boolean.FALSE))) return true;
waitForXCarrySafeSettle(mc, MacroConditionRegistry.inventorySyncRevision(), 3, 350L); waitForXCarrySafeSettle(mc, MacroConditionRegistry.inventorySyncRevision(), 3, 350L);
return Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, () -> xcarrySafeFinalMatches(mc, snapshot), Boolean.FALSE)); return Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, () -> xcarrySafeFinalMatches(mc, snapshot), Boolean.FALSE));
} }
private static boolean xcarrySafeFinalMatches(Minecraft mc, SafeGroupSnapshot snapshot) { private static boolean xcarrySafeFinalMatches(Minecraft mc, SafeGroupSnapshot snapshot) {
@ -719,11 +719,11 @@ final class MacroXCarry {
private static boolean returnXCarrySafeLeftovers(Minecraft mc, int preferredSlotId, ItemStack expected, private static boolean returnXCarrySafeLeftovers(Minecraft mc, int preferredSlotId, ItemStack expected,
int delayTicks, boolean delayBeforeReturn) throws InterruptedException { int delayTicks, boolean delayBeforeReturn) throws InterruptedException {
if (mc == null || mc.player == null || expected == null || expected.isEmpty()) return false; if (mc == null || mc.player == null || expected == null || expected.isEmpty()) return false;
if (MacroExecutor.callOnClientThread(mc, () -> mc.player != null && mc.player.inventoryMenu.getCarried().isEmpty(), Boolean.FALSE)) { if (MacroClientThread.callOnClientThread(mc, () -> mc.player != null && mc.player.inventoryMenu.getCarried().isEmpty(), Boolean.FALSE)) {
return true; return true;
} }
int returnSlot = MacroExecutor.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, preferredSlotId), -1); int returnSlot = MacroClientThread.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, preferredSlotId), -1);
if (returnSlot < 0) return false; if (returnSlot < 0) return false;
if (delayBeforeReturn) waitXCarrySafeDelayTicks(delayTicks); if (delayBeforeReturn) waitXCarrySafeDelayTicks(delayTicks);
return sendInventoryClickThenTick(mc, returnSlot, 0, ContainerInput.PICKUP) return sendInventoryClickThenTick(mc, returnSlot, 0, ContainerInput.PICKUP)
@ -769,8 +769,8 @@ final class MacroXCarry {
private static void rollbackXCarryCursorSafe(Minecraft mc, int sourceSlotId, int delayTicks, boolean delayBeforeReturn) throws InterruptedException { private static void rollbackXCarryCursorSafe(Minecraft mc, int sourceSlotId, int delayTicks, boolean delayBeforeReturn) throws InterruptedException {
if (mc == null || mc.player == null || mc.gameMode == null) return; if (mc == null || mc.player == null || mc.gameMode == null) return;
if (MacroExecutor.callOnClientThread(mc, () -> mc.player != null && mc.player.inventoryMenu.getCarried().isEmpty(), Boolean.FALSE)) return; if (MacroClientThread.callOnClientThread(mc, () -> mc.player != null && mc.player.inventoryMenu.getCarried().isEmpty(), Boolean.FALSE)) return;
int returnSlot = MacroExecutor.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, sourceSlotId), -1); int returnSlot = MacroClientThread.callOnClientThread(mc, () -> findXCarrySafeReturnSlot(mc, sourceSlotId), -1);
if (returnSlot >= 0) { if (returnSlot >= 0) {
if (delayBeforeReturn) waitXCarrySafeDelayTicks(delayTicks); if (delayBeforeReturn) waitXCarrySafeDelayTicks(delayTicks);
sendInventoryClickThenTick(mc, returnSlot, 0, ContainerInput.PICKUP); sendInventoryClickThenTick(mc, returnSlot, 0, ContainerInput.PICKUP);
@ -835,7 +835,7 @@ final class MacroXCarry {
} }
private static void rollbackXCarryCursor(Minecraft mc, int sourceSlotId) throws InterruptedException { private static void rollbackXCarryCursor(Minecraft mc, int sourceSlotId) throws InterruptedException {
MacroExecutor.runOnClientThread(mc, () -> { MacroClientThread.runOnClientThread(mc, () -> {
if (mc.player == null || mc.gameMode == null) return; if (mc.player == null || mc.gameMode == null) return;
net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu; net.minecraft.world.inventory.InventoryMenu handler = mc.player.inventoryMenu;
mc.player.containerMenu = handler; mc.player.containerMenu = handler;
@ -849,12 +849,12 @@ final class MacroXCarry {
private static boolean waitForXCarryCondition(Minecraft mc, long timeoutMs, java.util.function.Supplier<Boolean> condition) throws InterruptedException { private static boolean waitForXCarryCondition(Minecraft mc, long timeoutMs, java.util.function.Supplier<Boolean> condition) throws InterruptedException {
long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs); long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
while (MacroExecutor.isCurrentRunActive()) { while (MacroExecutor.isCurrentRunActive()) {
if (Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, condition, Boolean.FALSE))) { if (Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, condition, Boolean.FALSE))) {
return true; return true;
} }
if (System.nanoTime() >= deadline) break; if (System.nanoTime() >= deadline) break;
MacroExecutor.waitOneTick(); MacroExecutor.waitOneTick();
} }
return Boolean.TRUE.equals(MacroExecutor.callOnClientThread(mc, condition, Boolean.FALSE)); return Boolean.TRUE.equals(MacroClientThread.callOnClientThread(mc, condition, Boolean.FALSE));
} }
} }