diff --git a/src/main/java/anticope/rejects/mixin/meteor/modules/InventoryTweaksMixin.java b/src/main/java/anticope/rejects/mixin/meteor/modules/InventoryTweaksMixin.java new file mode 100644 index 0000000..e1731cc --- /dev/null +++ b/src/main/java/anticope/rejects/mixin/meteor/modules/InventoryTweaksMixin.java @@ -0,0 +1,27 @@ +package anticope.rejects.mixin.meteor.modules; + +import anticope.rejects.mixininterface.IInventoryTweaks; +import meteordevelopment.meteorclient.systems.modules.misc.InventoryTweaks; +import net.minecraft.screen.ScreenHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = InventoryTweaks.class, remap = false) +public abstract class InventoryTweaksMixin implements IInventoryTweaks { + private Runnable callback; + + @Inject(method = "lambda$steal$3", at = @At("RETURN")) + private void afterSteal(ScreenHandler handler, CallbackInfo info) { + if (callback != null) { + callback.run(); + callback = null; + } + } + + @Inject(method = "lambda$new$1", at = @At("HEAD")) + private void onStealChanged(Boolean b, CallbackInfo info) { + callback = null; + } +} diff --git a/src/main/java/anticope/rejects/mixininterface/IInventoryTweaks.java b/src/main/java/anticope/rejects/mixininterface/IInventoryTweaks.java new file mode 100644 index 0000000..b01649e --- /dev/null +++ b/src/main/java/anticope/rejects/mixininterface/IInventoryTweaks.java @@ -0,0 +1,5 @@ +package anticope.rejects.mixininterface; + +public interface IInventoryTweaks { + void afterSteal(Runnable callback); +} diff --git a/src/main/java/anticope/rejects/modules/ChestAura.java b/src/main/java/anticope/rejects/modules/ChestAura.java index 00695e4..9d2124a 100644 --- a/src/main/java/anticope/rejects/modules/ChestAura.java +++ b/src/main/java/anticope/rejects/modules/ChestAura.java @@ -1,57 +1,41 @@ package anticope.rejects.modules; import anticope.rejects.MeteorRejectsAddon; -import meteordevelopment.orbit.EventHandler; -import meteordevelopment.meteorclient.events.game.OpenScreenEvent; +import anticope.rejects.mixininterface.IInventoryTweaks; +import com.mojang.blaze3d.systems.RenderSystem; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.events.packets.InventoryEvent; import meteordevelopment.meteorclient.events.world.TickEvent; -import meteordevelopment.meteorclient.settings.BlockListSetting; -import meteordevelopment.meteorclient.settings.BoolSetting; -import meteordevelopment.meteorclient.settings.DoubleSetting; -import meteordevelopment.meteorclient.settings.EnumSetting; -import meteordevelopment.meteorclient.settings.IntSetting; -import meteordevelopment.meteorclient.settings.Setting; -import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.meteorclient.utils.misc.Pool; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.misc.InventoryTweaks; +import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.meteorclient.utils.player.Rotations; -import meteordevelopment.meteorclient.utils.world.BlockIterator; -import meteordevelopment.meteorclient.utils.world.BlockUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.minecraft.block.AbstractChestBlock; -import net.minecraft.block.AbstractFurnaceBlock; -import net.minecraft.block.BarrelBlock; -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import net.minecraft.block.BrewingStandBlock; -import net.minecraft.block.DispenserBlock; -import net.minecraft.block.ShulkerBoxBlock; -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; -import net.minecraft.item.Items; -import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket; -import net.minecraft.screen.GenericContainerScreenHandler; +import meteordevelopment.orbit.EventHandler; +import meteordevelopment.orbit.EventPriority; +import net.minecraft.block.BlockState; +import net.minecraft.block.ChestBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class ChestAura extends Module { - - public enum CloseScreen { - Always, - IfEmpty, - Never - } - private final SettingGroup sgGeneral = settings.getDefaultGroup(); - + private final Setting rotate = sgGeneral.add(new BoolSetting.Builder() .name("rotate") - .description("Rotates when placing") + .description("Rotates when opening.") .defaultValue(true) .build() ); @@ -64,157 +48,116 @@ public class ChestAura extends Module { .build() ); - private final Setting> blockTypes = sgGeneral.add(new BlockListSetting.Builder() - .name("storage-blocks") - .description("The blocks you open.") - .filter(this::predicate) - .defaultValue(Arrays.asList(Blocks.CHEST)) - .build() + private final Setting>> blocks = sgGeneral.add(new StorageBlockListSetting.Builder() + .name("blocks") + .description("The blocks you open.") + .defaultValue(BlockEntityType.CHEST) + .build() ); - private final Setting bpt = sgGeneral.add(new IntSetting.Builder() - .name("opens-per-tick") - .description("How many blocks to open per tick") - .defaultValue(2) - .min(1) - .sliderMax(8) - .build() + private final Setting delay = sgGeneral.add(new IntSetting.Builder() + .name("delay") + .description("Delay between opening chests.") + .defaultValue(10) + .sliderMax(20) + .build() ); - private final Setting forgetAfter = sgGeneral.add(new IntSetting.Builder() - .name("forget-after") - .description("How many ticks to wait before forgetting which chest to open. 0 for infinite") - .defaultValue(0) - .min(0) - .sliderMax(1000) - .build() + private final Setting forget = sgGeneral.add(new IntSetting.Builder() + .name("forget-after") + .description("How many ticks to wait before forgetting which chest to open. 0 for infinite.") + .defaultValue(0) + .min(0) + .sliderMax(1000) + .build() ); - private final Setting closeScreen = sgGeneral.add(new EnumSetting.Builder() - .name("close-screen") - .defaultValue(CloseScreen.IfEmpty) - .description("when to close the chest screen") - .build() + private final Setting closeCondition = sgGeneral.add(new EnumSetting.Builder() + .name("close-condition") + .defaultValue(CloseCondition.IfEmpty) + .description("When to close the chest screen.") + .build() ); - private final Pool blockPosPool = new Pool<>(BlockPos.Mutable::new); - private final List blocks = new ArrayList<>(); - private final List clickedBlocks = new ArrayList<>(); + private final Map openedBlocks = new HashMap<>(); + private final CloseListener closeListener = new CloseListener(); - int cap = 0; - int forget = 0; + private int timer = 0; public ChestAura() { super(MeteorRejectsAddon.CATEGORY, "chest-aura", "Automatically open chests in radius"); } @Override - public void onDeactivate() { - for (BlockPos.Mutable blockPos : blocks) blockPosPool.free(blockPos); - for (BlockPos.Mutable blockPos : clickedBlocks) blockPosPool.free(blockPos); - blocks.clear(); - clickedBlocks.clear(); + public void onActivate() { + timer = 0; + openedBlocks.clear(); } @EventHandler private void onTick(TickEvent.Pre event) { - - BlockIterator.register((int) Math.floor(range.get()), (int) Math.floor(range.get()), (blockPos, blockState) -> { - if (!BlockUtils.canBreak(blockPos, blockState)) return; - - if (!(blockTypes.get().contains(blockState.getBlock()))) return; - - if (clickedBlocks.contains(blockPos)) return; - - blocks.add(blockPosPool.get().set(blockPos)); - }); - - if (forgetAfter.get() > 0) { - if (forget >= forgetAfter.get()) { - forget = 0; - for (BlockPos.Mutable blockPos : clickedBlocks) blockPosPool.free(blockPos); - clickedBlocks.clear(); + if (forget.get() != 0) { + for (Map.Entry e : new HashMap<>(openedBlocks).entrySet()) { + int time = e.getValue(); + if (time > forget.get()) openedBlocks.remove(e.getKey()); + else openedBlocks.replace(e.getKey(), time + 1); } } - - } - @EventHandler - private void onTickPost(TickEvent.Post event) { - if (mc.currentScreen == null) { - for (BlockPos blockPos : blocks) { - if (clickedBlocks.contains(blockPos)) continue; - if (mc.currentScreen != null) return; - if (cap >= bpt.get()) { - cap = 0; - return; + if (timer > 0 && mc.currentScreen != null) return; + + for (BlockEntity block : Utils.blockEntities()) { + if (!blocks.get().contains(block.getType())) continue; + if (mc.player.getEyePos().distanceTo(Vec3d.ofCenter(block.getPos())) >= range.get()) continue; + + BlockPos pos = block.getPos(); + if (openedBlocks.containsKey(pos)) continue; + + Runnable click = () -> mc.interactionManager.interactBlock(mc.player, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(pos.getX(), pos.getY(), pos.getZ()), Direction.UP, pos, false)); + if (rotate.get()) Rotations.rotate(Rotations.getYaw(pos), Rotations.getPitch(pos), click); + else click.run(); + + // Double chest compatibility + BlockState state = block.getCachedState(); + if (state.contains(ChestBlock.CHEST_TYPE)) { + Direction direction = state.get(ChestBlock.FACING); + switch (state.get(ChestBlock.CHEST_TYPE)) { + case LEFT -> openedBlocks.put(pos.offset(direction.rotateYClockwise()), 0); + case RIGHT -> openedBlocks.put(pos.offset(direction.rotateYCounterclockwise()), 0); } - if (rotate.get()) { - Rotations.rotate(Rotations.getYaw(blockPos), Rotations.getPitch(blockPos), () -> { - click(blockPos); - clickedBlocks.add(blockPosPool.get().set(blockPos)); - }); - } else { - click(blockPos); - clickedBlocks.add(blockPosPool.get().set(blockPos)); - } - cap++; } - } else if (mc.currentScreen instanceof GenericContainerScreen containerScreen) { - closeIfEmpty(containerScreen.getScreenHandler()); + + openedBlocks.put(pos, 0); + timer = delay.get(); + MeteorClient.EVENT_BUS.subscribe(closeListener); + break; } - + timer--; } - private boolean predicate(Block block) { - return ( - block instanceof AbstractChestBlock || - block instanceof ShulkerBoxBlock || - block instanceof BarrelBlock || - block instanceof BrewingStandBlock || - block instanceof DispenserBlock || - block instanceof AbstractFurnaceBlock - ); - } - - private void click(BlockPos pos) { - mc.interactionManager.interactBlock(mc.player, Hand.MAIN_HAND, new BlockHitResult( - new Vec3d(pos.getX(), pos.getY(), pos.getZ()), - Direction.UP, - pos, - false - )); - } - - private void closeIfEmpty(GenericContainerScreenHandler handler) { - switch (closeScreen.get()) { - case IfEmpty: { - if (!handler.getInventory().containsAny(item -> { - return !item.isEmpty(); - })) { - if (!handler.getCursorStack().isEmpty()) return; - mc.getNetworkHandler().sendPacket(new CloseHandledScreenC2SPacket(handler.syncId)); - mc.setScreen(null); + public class CloseListener { + @EventHandler(priority = EventPriority.HIGH) + private void onInventory(InventoryEvent event) { + ScreenHandler handler = mc.player.currentScreenHandler; + if (event.packet.getSyncId() == handler.syncId) { + switch (closeCondition.get()) { + case IfEmpty -> { + if (handler.getStacks().stream().allMatch(ItemStack::isEmpty)) + mc.player.closeHandledScreen(); + } + case Always -> mc.player.closeHandledScreen(); + case AfterSteal -> + ((IInventoryTweaks) Modules.get().get(InventoryTweaks.class)).afterSteal(() -> RenderSystem.recordRenderCall(() -> mc.player.closeHandledScreen())); } - break; } - - case Always: { - mc.getNetworkHandler().sendPacket(new CloseHandledScreenC2SPacket(handler.syncId)); - mc.setScreen(null); - break; - } - - default: - break; + MeteorClient.EVENT_BUS.unsubscribe(this); } - } - @EventHandler - private void onOpenScreen(OpenScreenEvent event) { - if (!(event.screen instanceof GenericContainerScreen containerScreen)) return; - closeIfEmpty(containerScreen.getScreenHandler()); + public enum CloseCondition { + Always, + IfEmpty, + AfterSteal, + Never } - } diff --git a/src/main/resources/meteor-rejects-meteor.mixins.json b/src/main/resources/meteor-rejects-meteor.mixins.json index fac91ea..1aaaab3 100644 --- a/src/main/resources/meteor-rejects-meteor.mixins.json +++ b/src/main/resources/meteor-rejects-meteor.mixins.json @@ -12,6 +12,7 @@ "DefaultSettingsWidgetFactoryMixin", "modules.FlightMixin", "modules.NoRenderAccessor", - "modules.AutoSignMixin" + "modules.AutoSignMixin", + "modules.InventoryTweaksMixin" ] }