mirror of
https://github.com/AntiCope/meteor-rejects.git
synced 2025-09-06 12:25:49 +00:00
Chest aura improvements (#208)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package anticope.rejects.mixininterface;
|
||||
|
||||
public interface IInventoryTweaks {
|
||||
void afterSteal(Runnable callback);
|
||||
}
|
@@ -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<Boolean> 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<List<Block>> 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<List<BlockEntityType<?>>> blocks = sgGeneral.add(new StorageBlockListSetting.Builder()
|
||||
.name("blocks")
|
||||
.description("The blocks you open.")
|
||||
.defaultValue(BlockEntityType.CHEST)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> 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<Integer> delay = sgGeneral.add(new IntSetting.Builder()
|
||||
.name("delay")
|
||||
.description("Delay between opening chests.")
|
||||
.defaultValue(10)
|
||||
.sliderMax(20)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> 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<Integer> 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> closeScreen = sgGeneral.add(new EnumSetting.Builder<CloseScreen>()
|
||||
.name("close-screen")
|
||||
.defaultValue(CloseScreen.IfEmpty)
|
||||
.description("when to close the chest screen")
|
||||
.build()
|
||||
private final Setting<CloseCondition> closeCondition = sgGeneral.add(new EnumSetting.Builder<CloseCondition>()
|
||||
.name("close-condition")
|
||||
.defaultValue(CloseCondition.IfEmpty)
|
||||
.description("When to close the chest screen.")
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Pool<BlockPos.Mutable> blockPosPool = new Pool<>(BlockPos.Mutable::new);
|
||||
private final List<BlockPos.Mutable> blocks = new ArrayList<>();
|
||||
private final List<BlockPos.Mutable> clickedBlocks = new ArrayList<>();
|
||||
private final Map<BlockPos, Integer> 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<BlockPos, Integer> 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
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
"DefaultSettingsWidgetFactoryMixin",
|
||||
"modules.FlightMixin",
|
||||
"modules.NoRenderAccessor",
|
||||
"modules.AutoSignMixin"
|
||||
"modules.AutoSignMixin",
|
||||
"modules.InventoryTweaksMixin"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user