diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ShaderCapeFixMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ShaderCapeFixMixin.java new file mode 100644 index 0000000000..580d52b649 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ShaderCapeFixMixin.java @@ -0,0 +1,47 @@ +package meteordevelopment.meteorclient.mixin; + +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.lang.reflect.Field; + +@Pseudo +@Mixin(targets = "meteordevelopment.meteorclient.utils.render.CustomOutlineVertexConsumerProvider", remap = false) +public abstract class ShaderCapeFixMixin { + + /** + * method_22991 is the intermediary name for getBuffer. + * We target both to ensure compatibility with your environment. + */ + @Inject(method = {"getBuffer", "method_22991"}, at = @At("HEAD"), cancellable = true, remap = false) + private void onGetBuffer(RenderLayer layer, CallbackInfoReturnable cir) { + if (layer != null && layer.toString().toLowerCase().contains("cape")) { + try { + // We use Reflection to find the 'inner' provider field inside Meteor Client. + // This prevents the "Shadow field not located" crash. + for (Field field : this.getClass().getDeclaredFields()) { + if (VertexConsumerProvider.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + VertexConsumerProvider innerProvider = (VertexConsumerProvider) field.get(this); + + if (innerProvider != null) { + // Force the cape to render using the original world buffer + // instead of the broken translucent ESP shader. + cir.setReturnValue(innerProvider.getBuffer(layer)); + return; + } + } + } + } catch (Exception ignored) { + // If reflection fails, the cape stays invisible or ghosted, + // but the game won't crash. + } + } + } +} \ No newline at end of file diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java index fbb4ed2319..5d12dba564 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java @@ -393,6 +393,7 @@ public void add(Module module) { private void initCombat() { add(new AnchorAura()); + add(new AntiItemDestroy()); add(new AntiAnvil()); add(new AntiBed()); add(new ArrowDodge()); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AntiItemDestroy.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AntiItemDestroy.java new file mode 100644 index 0000000000..9d277e78b1 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AntiItemDestroy.java @@ -0,0 +1,85 @@ +package meteordevelopment.meteorclient.systems.modules.combat; + +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.settings.IntSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.systems.modules.Categories; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.orbit.EventHandler; +import meteordevelopment.orbit.EventPriority; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.EndCrystalEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Items; +import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; + +public class AntiItemDestroy extends Module { + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting delayTicks = sgGeneral.add(new IntSetting.Builder() + .name("delay-ticks") + .description("How many ticks to block interaction.") + .defaultValue(30) + .min(0) + .build() + ); + + private int blockTimer = 0; + + public AntiItemDestroy() { + super(Categories.Combat, "anti-item-destroy", "Instant-cancel for crystals and anchors upon kill."); + } + + @EventHandler + private void onTick(TickEvent.Post event) { + if (blockTimer > 0) blockTimer--; + + // Backup check: If a player is 0 HP but packet was missed + for (PlayerEntity player : mc.world.getPlayers()) { + if (player != mc.player && player.getHealth() <= 0 && mc.player.distanceTo(player) < 10) { + blockTimer = delayTicks.get(); + } + } + } + + // High Priority ensures this triggers BEFORE the game processes the death + @EventHandler(priority = EventPriority.HIGHEST) + private void onReceivePacket(PacketEvent.Receive event) { + if (event.packet instanceof EntityStatusS2CPacket packet) { + if (packet.getStatus() == 3) { // Status 3 = Death + Entity entity = packet.getEntity(mc.world); + if (entity instanceof PlayerEntity && entity != mc.player) { + if (mc.player.distanceTo(entity) < 10) { + blockTimer = delayTicks.get(); + // Optional: play a sound so you know it locked + // mc.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_BASS, 1, 1); + } + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + private void onSendPacket(PacketEvent.Send event) { + if (blockTimer <= 0) return; + + // BLOCK PLACING (Right Click) + if (event.packet instanceof PlayerInteractBlockC2SPacket packet) { + var item = mc.player.getStackInHand(packet.getHand()).getItem(); + if (item == Items.END_CRYSTAL || item == Items.RESPAWN_ANCHOR || item == Items.GLOWSTONE) { + event.cancel(); + } + } + + // BLOCK BREAKING (Left Click / Attack) + if (event.packet instanceof PlayerInteractEntityC2SPacket) { + // We cancel ALL entity interactions while the timer is active. + // This prevents you from "breaking" a crystal that was already there. + event.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/meteor-client.mixins.json b/src/main/resources/meteor-client.mixins.json index 660f9529d5..a0a35b2561 100644 --- a/src/main/resources/meteor-client.mixins.json +++ b/src/main/resources/meteor-client.mixins.json @@ -169,6 +169,7 @@ "SectionedEntityCacheAccessor", "ServerPlayerEntityMixin", "ServerResourcePackLoaderMixin", + "ShaderCapeFixMixin", "ShaderLoaderMixin", "ShadowPiecesCommandRendererMixin", "ShulkerBoxScreenHandlerAccessor",