From b98e0a1db589b3a2da2e2dcf28071ae5f245d6ea Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 10:52:05 +0530 Subject: [PATCH 1/9] Fixed Base place - works with meteor or genyo Added Sound Toggles for all Sounds Auto Portal renamed to GenyoAutoPortal Added GenyoLogoutPoints Added GenyoNoMineAnimation Fixed GenyoSelfTrap.java head place Fixed GenyoMineESP.java to depend on packet instead of hand swing. --- src/main/java/com/genyo/Genyo.java | 1 + src/main/java/com/genyo/core/Core.java | 22 +- .../genyo/managers/combat/CombatManager.java | 6 +- .../mixin/accessor/AccessorCrystalAura.java | 11 + .../com/genyo/mixin/meteor/MixinWWidget.java | 16 +- .../render/MixinWorldRendererBreaking.java | 22 ++ .../com/genyo/systems/config/GenyoConfig.java | 121 ++++++++- .../systems/modules/combat/BasePlace.java | 21 +- .../systems/modules/combat/GenyoMineESP.java | 168 ++++++++---- .../systems/modules/misc/GenyoAutoPortal.java | 2 +- .../modules/visual/GenyoLogoutPoints.java | 247 ++++++++++++++++++ .../modules/visual/GenyoNoMineAnimation.java | 51 ++++ .../systems/modules/world/GenyoSelfTrap.java | 56 +++- src/main/resources/genyo.mixins.json | 4 +- 14 files changed, 664 insertions(+), 84 deletions(-) create mode 100644 src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java create mode 100644 src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java create mode 100644 src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java create mode 100644 src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index ff148ae..1e1f4e0 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -134,6 +134,7 @@ private void initSystems() { private void initModules(Modules modules) { modules.add(new GenyoAutoEZ()); + modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); modules.add(new GenyoNuker()); diff --git a/src/main/java/com/genyo/core/Core.java b/src/main/java/com/genyo/core/Core.java index 2eb6dc9..81163fa 100644 --- a/src/main/java/com/genyo/core/Core.java +++ b/src/main/java/com/genyo/core/Core.java @@ -54,19 +54,26 @@ private float humanizeVolume(float min, float max) { @EventHandler public void onMessageReceive(ReceiveMessageEvent event) { String message = event.getMessage().getString().toLowerCase(); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg == null) return; if (message.contains("genyo") && !message.startsWith("§")) { - Managers.SOUND.playSound(VINE); + if (cfg.vineSound.get()) { + Managers.SOUND.playSound(VINE, cfg.vineVolume.get()); + } } else if (message.contains("verstappen")) { - Managers.SOUND.playSound(VERSTAPPEN); - } else if ((message.contains("nigga") || message.contains("nigger")) && - (GenyoConfig.get().blackPerson.get()) && GenyoConfig.get() != null) { + if (cfg.verstappenSound.get()) { + Managers.SOUND.playSound(VERSTAPPEN, cfg.verstappenVolume.get()); + } + } else if ((message.contains("nigga") || message.contains("nigger")) && cfg.blackPerson.get()) { if (soundTimer.passed(6000)) { Managers.SOUND.playSound(BLACK, 10); soundTimer.reset(); } } else if (message.contains("kiwi")) { - Managers.SOUND.playSound(KIWI); + if (cfg.kiwiSound.get()) { + Managers.SOUND.playSound(KIWI, cfg.kiwiVolume.get()); + } } } @@ -75,7 +82,10 @@ public void onPlayerRender(EntityAddedEvent event) { if (!(event.entity instanceof PlayerEntity player)) return; if (!Enemies.get().isEnemy(player)) return; - Managers.SOUND.playSound(HAMBURGER); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg != null && cfg.hamburgerSound.get()) { + Managers.SOUND.playSound(HAMBURGER, cfg.hamburgerVolume.get()); + } } } diff --git a/src/main/java/com/genyo/managers/combat/CombatManager.java b/src/main/java/com/genyo/managers/combat/CombatManager.java index 5fe767d..39bfeda 100644 --- a/src/main/java/com/genyo/managers/combat/CombatManager.java +++ b/src/main/java/com/genyo/managers/combat/CombatManager.java @@ -4,6 +4,7 @@ import com.genyo.events.UnderCombatEvent; import com.genyo.managers.Managers; import com.genyo.core.sound.SoundManager; +import com.genyo.systems.config.GenyoConfig; import com.genyo.utils.GenyoChatUtils; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.events.entity.player.AttackEntityEvent; @@ -61,7 +62,10 @@ public void onPacketReceive(PacketEvent.Receive event) { "\n\nReason: " + Formatting.GREEN + "ewrhjfkjerkjfhrejkgkregr" + Formatting.GRAY + "\nConclusion: " + Formatting.GREEN + "Skill issue. :("); - Managers.SOUND.playSound(SoundManager.SCREAM, 80); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg != null && cfg.screamSound.get()) { + Managers.SOUND.playSound(SoundManager.SCREAM, cfg.screamVolume.get()); + } } } } diff --git a/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java b/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java new file mode 100644 index 0000000..07747bf --- /dev/null +++ b/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java @@ -0,0 +1,11 @@ +package com.genyo.mixin.accessor; + +import meteordevelopment.meteorclient.systems.modules.combat.CrystalAura; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CrystalAura.class) +public interface AccessorCrystalAura { + @Accessor("placing") + boolean isPlacing(); +} diff --git a/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java b/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java index 0a23237..d468849 100644 --- a/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java +++ b/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java @@ -28,7 +28,7 @@ private void onMouseMoved(double mouseX, double mouseY, if (mouseOver && !genyo_wasOver) { GenyoConfig cfg = GenyoConfig.get(); - if (cfg != null && cfg.guiSounds.get()) { + if (cfg != null && cfg.hoverSoundEnabled.get()) { float vol = cfg.hoverVolume.get() / 100f; Managers.SOUND.playUISound(SoundManager.GUI_HOVER, vol, 1f); } @@ -44,14 +44,18 @@ private void onMouseClicked(Click click, boolean doubled, if (!mouseOver) return; GenyoConfig cfg = GenyoConfig.get(); - if (cfg == null || !cfg.guiSounds.get()) return; - - float vol = cfg.clickVolume.get() / 100f; + if (cfg == null) return; if (click.button() == 0) { - Managers.SOUND.playUISound(SoundManager.GUI_CLICK_LEFT, vol, 1f); + if (cfg.clickLeftSoundEnabled.get()) { + float vol = cfg.clickLeftVolume.get() / 100f; + Managers.SOUND.playUISound(SoundManager.GUI_CLICK_LEFT, vol, 1f); + } } else if (click.button() == 1) { - Managers.SOUND.playUISound(SoundManager.GUI_CLICK_RIGHT, vol, 1f); + if (cfg.clickRightSoundEnabled.get()) { + float vol = cfg.clickRightVolume.get() / 100f; + Managers.SOUND.playUISound(SoundManager.GUI_CLICK_RIGHT, vol, 1f); + } } } } diff --git a/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java b/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java new file mode 100644 index 0000000..c6b5f15 --- /dev/null +++ b/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java @@ -0,0 +1,22 @@ +package com.genyo.mixin.render; + +import com.genyo.systems.modules.visual.GenyoNoMineAnimation; +import meteordevelopment.meteorclient.systems.modules.Modules; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.util.math.BlockPos; +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(WorldRenderer.class) +public abstract class MixinWorldRendererBreaking { + + @Inject(method = "setBlockBreakingInfo", at = @At("HEAD"), cancellable = true) + private void genyo$hookSetBlockBreakingInfo(int breakerId, BlockPos pos, int stage, CallbackInfo ci) { + GenyoNoMineAnimation module = Modules.get().get(GenyoNoMineAnimation.class); + if (module != null && module.shouldCancel(breakerId)) { + ci.cancel(); + } + } +} diff --git a/src/main/java/com/genyo/systems/config/GenyoConfig.java b/src/main/java/com/genyo/systems/config/GenyoConfig.java index 7ccd1bc..30dab78 100644 --- a/src/main/java/com/genyo/systems/config/GenyoConfig.java +++ b/src/main/java/com/genyo/systems/config/GenyoConfig.java @@ -33,11 +33,9 @@ public class GenyoConfig extends System { .build() ); - // In sgSounds group, add these three: - - public final Setting guiSounds = sgSounds.add(new BoolSetting.Builder() - .name("gui-sounds") - .description("Play sounds when hovering and clicking in Meteor's GUI.") + public final Setting hoverSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("hover-sound") + .description("Play a sound when hovering over a module in Meteor's GUI.") .defaultValue(true) .build() ); @@ -47,16 +45,39 @@ public class GenyoConfig extends System { .description("Volume of the hover sound.") .min(1).defaultValue(60).max(100) .sliderRange(1, 100) - .visible(guiSounds::get) + .visible(hoverSoundEnabled::get) + .build() + ); + + public final Setting clickLeftSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("click-left-sound") + .description("Play a sound when left-clicking a module in Meteor's GUI.") + .defaultValue(true) + .build() + ); + + public final Setting clickLeftVolume = sgSounds.add(new IntSetting.Builder() + .name("click-left-volume") + .description("Volume of the left-click sound.") + .min(1).defaultValue(80).max(100) + .sliderRange(1, 100) + .visible(clickLeftSoundEnabled::get) + .build() + ); + + public final Setting clickRightSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("click-right-sound") + .description("Play a sound when right-clicking a module in Meteor's GUI.") + .defaultValue(true) .build() ); - public final Setting clickVolume = sgSounds.add(new IntSetting.Builder() - .name("click-volume") - .description("Volume of left/right click sounds.") + public final Setting clickRightVolume = sgSounds.add(new IntSetting.Builder() + .name("click-right-volume") + .description("Volume of the right-click sound.") .min(1).defaultValue(80).max(100) .sliderRange(1, 100) - .visible(guiSounds::get) + .visible(clickRightSoundEnabled::get) .build() ); @@ -83,6 +104,86 @@ public class GenyoConfig extends System { .build() ); + public final Setting vineSound = sgSounds.add(new BoolSetting.Builder() + .name("vine-sound") + .description("Play a sound when someone says 'genyo' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting vineVolume = sgSounds.add(new IntSetting.Builder() + .name("vine-volume") + .description("Volume of the vine sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(vineSound::get) + .build() + ); + + public final Setting verstappenSound = sgSounds.add(new BoolSetting.Builder() + .name("verstappen-sound") + .description("Play a sound when someone says 'verstappen' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting verstappenVolume = sgSounds.add(new IntSetting.Builder() + .name("verstappen-volume") + .description("Volume of the verstappen sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(verstappenSound::get) + .build() + ); + + public final Setting kiwiSound = sgSounds.add(new BoolSetting.Builder() + .name("kiwi-sound") + .description("Play a sound when someone says 'kiwi' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting kiwiVolume = sgSounds.add(new IntSetting.Builder() + .name("kiwi-volume") + .description("Volume of the kiwi sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(kiwiSound::get) + .build() + ); + + public final Setting hamburgerSound = sgSounds.add(new BoolSetting.Builder() + .name("hamburger-sound") + .description("Play a sound when an enemy player renders in.") + .defaultValue(true) + .build() + ); + + public final Setting hamburgerVolume = sgSounds.add(new IntSetting.Builder() + .name("hamburger-volume") + .description("Volume of the hamburger sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(hamburgerSound::get) + .build() + ); + + public final Setting screamSound = sgSounds.add(new BoolSetting.Builder() + .name("scream-sound") + .description("Play a sound when you die.") + .defaultValue(true) + .build() + ); + + public final Setting screamVolume = sgSounds.add(new IntSetting.Builder() + .name("scream-volume") + .description("Volume of the scream sound.") + .min(1).defaultValue(80).max(100) + .sliderRange(1, 100) + .visible(screamSound::get) + .build() + ); + // Visual public final Setting useGenyoSplashes = sgVisual.add(new BoolSetting.Builder() diff --git a/src/main/java/com/genyo/systems/modules/combat/BasePlace.java b/src/main/java/com/genyo/systems/modules/combat/BasePlace.java index a5d5e65..97217cb 100644 --- a/src/main/java/com/genyo/systems/modules/combat/BasePlace.java +++ b/src/main/java/com/genyo/systems/modules/combat/BasePlace.java @@ -3,6 +3,7 @@ import com.genyo.Genyo; import com.genyo.events.network.PlayerTickEvent; import com.genyo.managers.Managers; +import com.genyo.mixin.accessor.AccessorCrystalAura; import com.genyo.render.animation.Animation; import com.genyo.systems.modules.PlacerModule; import com.genyo.systems.settings.FloatSetting; @@ -126,7 +127,22 @@ public void onDeactivate() { @EventHandler public void onTick(PlayerTickEvent event) { - if (!Modules.get().isActive(GenyoAutoCrystal.class) || !Modules.get().isActive(CrystalAura.class) || Modules.get().get(GenyoAutoCrystal.class).isPlacing()) + boolean genyoActive = Modules.get().isActive(GenyoAutoCrystal.class); + boolean caActive = Modules.get().isActive(CrystalAura.class); + + // Neither aura running -> nothing for base-place to support + if (!genyoActive && !caActive) + { + return; + } + + // Don't interfere while the active aura is itself mid-placement + if (genyoActive && Modules.get().get(GenyoAutoCrystal.class).isPlacing()) + { + return; + } + + if (caActive && ((AccessorCrystalAura) Modules.get().get(CrystalAura.class)).isPlacing()) { return; } @@ -216,7 +232,8 @@ private BlockPos getCrystalBase(PlayerEntity player) continue; } - if (!Modules.get().get(GenyoAutoCrystal.class).isCrystalHitboxClear(pos)) + if (Modules.get().isActive(GenyoAutoCrystal.class) + && !Modules.get().get(GenyoAutoCrystal.class).isCrystalHitboxClear(pos)) { continue; } diff --git a/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java b/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java index 4e84eef..45e0d64 100644 --- a/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java +++ b/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java @@ -17,14 +17,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import org.joml.Vector3d; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class GenyoMineESP extends Module { @@ -47,7 +44,7 @@ public enum RenderMode { private final Setting syncDoubleMine = sgGeneral.add(new BoolSetting.Builder() .name("sync-double-mine") - .description("Próbálja meg kitalálni és szinkronizálni a második bányászott blokkot (Heurisztikus).") + .description("Jelzi, ha ugyanaz a játékos egyszerre több blokkot is bányászik (szerver csomagok alapján).") .defaultValue(true) .build() ); @@ -59,6 +56,13 @@ public enum RenderMode { .build() ); + private final Setting showOwnMining = sgGeneral.add(new BoolSetting.Builder() + .name("show-own-mining") + .description("Az ESP a saját bányászásunkat is mutassa.") + .defaultValue(false) + .build() + ); + private final Setting customFont = sgGeneral.add(new BoolSetting.Builder() .name("custom-font") .description("Meteor egyedi betűtípusának használata.") @@ -79,6 +83,19 @@ public enum RenderMode { .build() ); + private final Setting doubleMineSideColor = sgColors.add(new ColorSetting.Builder() + .name("double-mine-side-color") + .description("A doboz színe, ha a játékos egyszerre több blokkot bányászik.") + .defaultValue(new SettingColor(255, 165, 0, 100)) + .build() + ); + + private final Setting doubleMineLineColor = sgColors.add(new ColorSetting.Builder() + .name("double-mine-line-color") + .defaultValue(new SettingColor(255, 165, 0, 255)) + .build() + ); + private final Setting textColor = sgColors.add(new ColorSetting.Builder() .name("text-color") .defaultValue(new SettingColor(255, 255, 255, 255)) @@ -110,30 +127,22 @@ public enum RenderMode { ); private final Map blocks = new ConcurrentHashMap<>(); - private final Map suspectedMines = new ConcurrentHashMap<>(); private final Map lastBrokenBlocks = new ConcurrentHashMap<>(); - private final Set swingingEntities = ConcurrentHashMap.newKeySet(); + private BlockPos selfBreakingPos = null; public GenyoMineESP() { - super(Genyo.COMBAT, "mine-esp", "Fejlett ESP Liquid effekttel, Double Mine és Rebreak szinkronnal."); + super(Genyo.COMBAT, "genyo-mine-esp", "Fejlett ESP Liquid effekttel, Double Mine és Rebreak szinkronnal."); } @Override public void onDeactivate() { blocks.clear(); - suspectedMines.clear(); lastBrokenBlocks.clear(); - swingingEntities.clear(); + selfBreakingPos = null; } @EventHandler private void onReceivePacket(PacketEvent.Receive event) { - if (event.packet instanceof EntityAnimationS2CPacket animPacket) { - if (animPacket.getAnimationId() == 0 || animPacket.getAnimationId() == 3) { - swingingEntities.add(animPacket.getEntityId()); - } - } - if (event.packet instanceof BlockBreakingProgressS2CPacket packet) { BlockPos pos = packet.getPos(); int stage = packet.getProgress(); @@ -157,23 +166,7 @@ private void onReceivePacket(PacketEvent.Receive event) { @EventHandler private void onTick(TickEvent.Pre event) { - if (syncDoubleMine.get()) { - for (int entityId : swingingEntities) { - Entity entity = mc.world.getEntityById(entityId); - if (entity instanceof PlayerEntity && entity != mc.player) { - HitResult hit = entity.raycast(6.0, 1.0f, false); - if (hit instanceof BlockHitResult blockHit) { - BlockPos hitPos = blockHit.getBlockPos(); - if (!mc.world.getBlockState(hitPos).isAir()) { - suspectedMines.put(entityId, hitPos); - } - } - } - } - } - swingingEntities.clear(); - - suspectedMines.entrySet().removeIf(entry -> mc.world.getBlockState(entry.getValue()).isAir()); + updateOwnMining(); blocks.entrySet().removeIf(entry -> { MineData data = entry.getValue(); @@ -183,6 +176,68 @@ private void onTick(TickEvent.Pre event) { data.renderProgress += (target - data.renderProgress) * 0.15; return false; }); + + if (syncDoubleMine.get()) { + Map activeCounts = new ConcurrentHashMap<>(); + for (MineData data : blocks.values()) { + activeCounts.merge(data.entityId, 1, Integer::sum); + } + for (MineData data : blocks.values()) { + data.isDoubleMine = activeCounts.getOrDefault(data.entityId, 0) > 1; + } + } else { + for (MineData data : blocks.values()) { + data.isDoubleMine = false; + } + } + } + + private void updateOwnMining() { + if (mc.player == null || mc.interactionManager == null || !showOwnMining.get()) { + if (selfBreakingPos != null) { + blocks.remove(selfBreakingPos); + selfBreakingPos = null; + } + return; + } + + boolean breakingNow = mc.interactionManager.isBreakingBlock() && mc.crosshairTarget instanceof BlockHitResult; + + if (!breakingNow) { + if (selfBreakingPos != null) { + // If the block wasn't actually mined (i.e. we aborted), remove it immediately + // instead of waiting for the timeout. A finished block is already air and gets + // cleaned up by the removeIf air-check right after this runs. + if (!mc.world.getBlockState(selfBreakingPos).isAir()) { + blocks.remove(selfBreakingPos); + } + selfBreakingPos = null; + } + return; + } + + BlockHitResult hit = (BlockHitResult) mc.crosshairTarget; + BlockPos pos = hit.getBlockPos(); + int entityId = mc.player.getId(); + + int stage = mc.interactionManager.getBlockBreakingProgress(); + if (stage < 0) { + stage = 0; + } + + if (selfBreakingPos != null && !selfBreakingPos.equals(pos)) { + blocks.remove(selfBreakingPos); + } + + MineData data = blocks.get(pos); + if (data == null) { + boolean isRebreak = pos.equals(lastBrokenBlocks.get(entityId)); + blocks.put(pos, new MineData(pos, entityId, stage, isRebreak)); + } else { + data.targetStage = stage; + data.timer = 0; + } + selfBreakingPos = pos; } @EventHandler @@ -191,12 +246,6 @@ private void onRender3D(Render3DEvent event) { for (MineData data : blocks.values()) { renderBox(event, data.pos, data); - if (syncDoubleMine.get()) { - BlockPos suspected = suspectedMines.get(data.entityId); - if (suspected != null && !suspected.equals(data.pos)) { - renderBox(event, suspected, data); - } - } } } @@ -206,20 +255,24 @@ private void onRender2D(Render2DEvent event) { for (MineData data : blocks.values()) { renderText(event, data.pos, data); - if (syncDoubleMine.get()) { - BlockPos suspected = suspectedMines.get(data.entityId); - if (suspected != null && !suspected.equals(data.pos)) { - renderText(event, suspected, data); - } - } } } private void renderBox(Render3DEvent event, BlockPos pos, MineData data) { if (mc.player.squaredDistanceTo(pos.toCenterPos()) > radius.get() * radius.get()) return; - Color currentSide = data.isRebreak ? rebreakSideColor.get() : lerpColor(sideColorStart.get(), sideColorEnd.get(), data.renderProgress); - Color currentLine = data.isRebreak ? rebreakLineColor.get() : lerpColor(lineColorStart.get(), lineColorEnd.get(), data.renderProgress); + Color currentSide; + Color currentLine; + if (data.isRebreak) { + currentSide = rebreakSideColor.get(); + currentLine = rebreakLineColor.get(); + } else if (data.isDoubleMine) { + currentSide = doubleMineSideColor.get(); + currentLine = doubleMineLineColor.get(); + } else { + currentSide = lerpColor(sideColorStart.get(), sideColorEnd.get(), data.renderProgress); + currentLine = lerpColor(lineColorStart.get(), lineColorEnd.get(), data.renderProgress); + } if (renderMode.get() == RenderMode.Liquid) { double time = System.currentTimeMillis() / 200.0; @@ -261,13 +314,22 @@ private void renderText(Render2DEvent event, BlockPos pos, MineData data) { Vector3d pos2d = new Vector3d(pos3d); if (NametagUtils.to2D(pos2d, 1.5)) { + String tag = null; + Color tagColor = null; + if (data.isRebreak) { + tag = "Rebreak"; + tagColor = rebreakLineColor.get(); + } else if (data.isDoubleMine) { + tag = "Double Mine"; + tagColor = doubleMineLineColor.get(); + } + if (customFont.get()) { NametagUtils.begin(pos3d); TextRenderer.get().begin(1.0, false, true); TextRenderer.get().render(text, -TextRenderer.get().getWidth(text) / 2.0, 0, textColor.get(), true); - if (data.isRebreak) { - String rb = "Rebreak"; - TextRenderer.get().render(rb, -TextRenderer.get().getWidth(rb) / 2.0, 12, rebreakLineColor.get(), true); + if (tag != null) { + TextRenderer.get().render(tag, -TextRenderer.get().getWidth(tag) / 2.0, 12, tagColor, true); } TextRenderer.get().end(); NametagUtils.end(); @@ -276,10 +338,9 @@ private void renderText(Render2DEvent event, BlockPos pos, MineData data) { int x = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(text) / 2); int y = (int) (pos2d.y / scale); event.drawContext.drawTextWithShadow(mc.textRenderer, text, x, y, textColor.get().getPacked()); - if (data.isRebreak) { - String rb = "Rebreak"; - int rbX = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(rb) / 2); - event.drawContext.drawTextWithShadow(mc.textRenderer, rb, rbX, y + 10, rebreakLineColor.get().getPacked()); + if (tag != null) { + int tagX = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(tag) / 2); + event.drawContext.drawTextWithShadow(mc.textRenderer, tag, tagX, y + 10, tagColor.getPacked()); } } } @@ -300,6 +361,7 @@ private static class MineData { public double renderProgress; public int timer; public boolean isRebreak; + public boolean isDoubleMine; public MineData(BlockPos pos, int entityId, int stage, boolean isRebreak) { this.pos = pos; diff --git a/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java b/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java index d6fe582..a9ba699 100644 --- a/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java +++ b/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java @@ -82,7 +82,7 @@ public class GenyoAutoPortal extends Module { ); public GenyoAutoPortal() { - super(Genyo.MISC, "auto-portal", "Builds a Nether portal with Delay, Auto-Refill, and Hotbar Cleanup."); + super(Genyo.MISC, "genyo-auto-portal", "Builds a Nether portal with Delay, Auto-Refill, and Hotbar Cleanup."); } private final List frameBlocks = new ArrayList<>(); diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java new file mode 100644 index 0000000..139806e --- /dev/null +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java @@ -0,0 +1,247 @@ +package com.genyo.systems.modules.visual; + +import com.genyo.Genyo; +import com.genyo.render.animation.Animation; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.render.Render2DEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.renderer.text.TextRenderer; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.render.NametagUtils; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import org.joml.Vector3d; + +import java.text.DecimalFormat; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class GenyoLogoutPoints extends Module { + + private static final DecimalFormat DECIMAL = new DecimalFormat("#.#"); + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting showDistance = sgGeneral.add(new BoolSetting.Builder() + .name("distance") + .description("Shows distance from the logout.") + .defaultValue(false) + .build() + ); + + private final Setting showTimePassed = sgGeneral.add(new BoolSetting.Builder() + .name("time-passed") + .description("Shows time passed since logout.") + .defaultValue(false) + .build() + ); + + private final Setting fadeTime = sgGeneral.add(new IntSetting.Builder() + .name("fade-time") + .description("How long the fade in/out animation takes, in milliseconds.") + .min(0) + .defaultValue(500) + .max(2000) + .build() + ); + + private final Setting boxColor = sgGeneral.add(new ColorSetting.Builder() + .name("box-color") + .description("Color of the logout marker outline.") + .defaultValue(new SettingColor(255, 255, 255, 255)) + .build() + ); + + private final Setting textColor = sgGeneral.add(new ColorSetting.Builder() + .name("text-color") + .description("Color of the logout tag text.") + .defaultValue(new SettingColor(255, 255, 255, 255)) + .build() + ); + + private final Map onlinePlayers = new ConcurrentHashMap<>(); + private final Map offlinePlayers = new ConcurrentHashMap<>(); + + public GenyoLogoutPoints() { + super(Genyo.VISUAL, "genyo-logout-points", "Marks nearby logouts."); + } + + @Override + public void onDeactivate() { + onlinePlayers.clear(); + offlinePlayers.clear(); + } + + @EventHandler + public void onTick(TickEvent.Post event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (PlayerEntity player : mc.world.getPlayers()) { + if (player != null && player.getGameProfile() != null && !player.equals(mc.player)) { + onlinePlayers.put(player.getGameProfile().id(), new LogoutData(player, fadeTime.get())); + } + } + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) { + if (mc.player == null || mc.world == null) { + return; + } + + if (event.packet instanceof PlayerListS2CPacket packet + && packet.getActions().contains(PlayerListS2CPacket.Action.ADD_PLAYER)) { + for (PlayerListS2CPacket.Entry entry : packet.getPlayerAdditionEntries()) { + LogoutData data = offlinePlayers.get(entry.profile().id()); + if (data != null) { + data.setState(false); + } + } + + onlinePlayers.clear(); + } else if (event.packet instanceof PlayerRemoveS2CPacket packet) { + List profileIds = packet.profileIds(); + for (UUID uuid : profileIds) { + LogoutData data = onlinePlayers.get(uuid); + if (data == null) { + continue; + } + + if (!offlinePlayers.containsKey(uuid)) { + offlinePlayers.put(uuid, data); + data.setState(true); + } + } + + onlinePlayers.clear(); + } + } + + @EventHandler + public void onRender3D(Render3DEvent event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (Map.Entry set : offlinePlayers.entrySet()) { + LogoutData data = set.getValue(); + if (data == null) { + continue; + } + + double factor = data.getAnimation().getFactor(); + if (!data.getAnimation().getState() && factor <= 0.01) { + offlinePlayers.remove(set.getKey()); + continue; + } + + PlayerEntity offlinePlayer = data.getOfflinePlayer(); + Box box = offlinePlayer.getBoundingBox(); + + Color lineColor = boxColor.get().a((int) (boxColor.get().a * factor)); + Color sideColor = lineColor.a((int) (lineColor.a * 0.4)); + + event.renderer.box( + box.minX, box.minY, box.minZ, + box.maxX, box.maxY, box.maxZ, + sideColor, lineColor, ShapeMode.Lines, 0 + ); + } + } + + @EventHandler + public void onRender2D(Render2DEvent event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (LogoutData data : offlinePlayers.values()) { + double factor = data.getAnimation().getFactor(); + if (factor <= 0.01) { + continue; + } + + PlayerEntity offlinePlayer = data.getOfflinePlayer(); + Box box = offlinePlayer.getBoundingBox(); + + StringBuilder logoutTag = new StringBuilder(offlinePlayer.getName().getString() + "'s Logout"); + + boolean hasExtraInfo = false; + if (showDistance.get()) { + hasExtraInfo = true; + double dist = Math.sqrt(mc.player.squaredDistanceTo(offlinePlayer.getEntityPos())); + logoutTag.append(" - ").append(DECIMAL.format(dist)).append("m"); + } + + if (showTimePassed.get()) { + if (!hasExtraInfo) { + logoutTag.append(" -"); + } + + long seconds = (System.currentTimeMillis() - data.getLogoutTime()) / 1000; + if (seconds < 60) { + logoutTag.append(" ").append(seconds).append("s"); + } else { + long minutes = seconds / 60; + logoutTag.append(" ").append(minutes).append("min"); + } + } + + Vec3d center = box.getCenter(); + Vector3d pos3d = new Vector3d(center.x, box.maxY + 0.2, center.z); + Vector3d pos2d = new Vector3d(pos3d); + + if (NametagUtils.to2D(pos2d, 1.5)) { + Color currentTextColor = textColor.get().a((int) (textColor.get().a * factor)); + String tag = logoutTag.toString(); + + NametagUtils.begin(pos3d); + TextRenderer.get().begin(1.0, false, true); + TextRenderer.get().render(tag, -TextRenderer.get().getWidth(tag) / 2.0, 0, currentTextColor, true); + TextRenderer.get().end(); + NametagUtils.end(); + } + } + } + + private static class LogoutData { + private final PlayerEntity offlinePlayer; + private final long logoutTime; + private final Animation animation; + + public LogoutData(PlayerEntity offlinePlayer, float fadeLength) { + this.offlinePlayer = offlinePlayer; + this.logoutTime = System.currentTimeMillis(); + this.animation = new Animation(false, fadeLength); + } + + public PlayerEntity getOfflinePlayer() { + return offlinePlayer; + } + + public long getLogoutTime() { + return logoutTime; + } + + public Animation getAnimation() { + return animation; + } + + public void setState(boolean state) { + this.animation.setState(state); + } + } +} diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java b/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java new file mode 100644 index 0000000..f56d5d4 --- /dev/null +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java @@ -0,0 +1,51 @@ +package com.genyo.systems.modules.visual; + + + +import com.genyo.Genyo; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; + +public class GenyoNoMineAnimation extends Module { + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + public final Setting mode = sgGeneral.add(new EnumSetting.Builder() + .name("mode") + .description("Whose block-breaking animation to hide.") + .defaultValue(Mode.Everyone) + .build() + ); + + private final Setting hideParticles = sgGeneral.add(new BoolSetting.Builder() + .name("hide-particles") + .description("Also hides the block-breaking particles.") + .defaultValue(true) + .build() + ); + + public GenyoNoMineAnimation() { + super(Genyo.VISUAL, "genyo-no-mine-animation", "Hides the block-breaking (crack) animation."); + } + + // Used by the mixin to decide whether to cancel a given breaking-info update. + public boolean shouldCancel(int breakerId) { + if (!isActive()) return false; + + boolean isSelf = mc.player != null && breakerId == mc.player.getId(); + + return switch (mode.get()) { + case Everyone -> true; + case OthersOnly -> !isSelf; + case SelfOnly -> isSelf; + }; + } + + public boolean hideParticles() { + return isActive() && hideParticles.get(); + } + + public enum Mode { + Everyone, OthersOnly, SelfOnly + } +} diff --git a/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java b/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java index 15ab32a..05aba73 100644 --- a/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java +++ b/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java @@ -15,6 +15,7 @@ import meteordevelopment.meteorclient.renderer.ShapeMode; import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.player.AirPlace; import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; @@ -105,7 +106,14 @@ public GenyoSelfTrap() { private final Setting head = sgGeneral.add(new BoolSetting.Builder() .name("Cover Head") - .description("Doesn't work rn") + .description("Places a block above the player's head.") + .defaultValue(false) + .build() + ); + + private final Setting antiStep = sgGeneral.add(new BoolSetting.Builder() + .name("Prevent Step") + .description("Prevents the player from stepping out of the trap") .defaultValue(false) .build() ); @@ -487,10 +495,50 @@ public List getSurround(PlayerEntity player) } } - /*if (AirPlaceModule.getInstance().isEnabled() && head.get()) + if (head.get()) { - surroundBlocks.add(mc.player.getBlockPos().up(2)); - }*/ + boolean supported = false; + final List headBlocks = new ArrayList<>(); + for (BlockPos pos : playerBlocks) + { + BlockPos headPos = pos.offset(Direction.UP, 2); + if (!mc.world.getBlockState(headPos).isReplaceable()) + { + supported = true; + } + headBlocks.add(headPos); + if (antiStep.get()) + { + BlockPos antiStepPos = pos.offset(Direction.UP, 3); + headBlocks.add(antiStepPos); + } + } + if (!Modules.get().isActive(AirPlace.class)) + { + BlockPos supportingPos = null; + double min = Double.MAX_VALUE; + for (BlockPos pos : surroundBlocks) + { + BlockPos pos1 = pos.offset(Direction.UP, 2); + if (!mc.world.getBlockState(pos1).isReplaceable()) + { + supported = true; + break; + } + double dist = mc.player.squaredDistanceTo(pos1.toCenterPos()); + if (dist < min) + { + supportingPos = pos1; + min = dist; + } + } + if (supportingPos != null && !supported) + { + surroundBlocks.add(supportingPos); + } + } + surroundBlocks.addAll(headBlocks); + } return surroundBlocks; } diff --git a/src/main/resources/genyo.mixins.json b/src/main/resources/genyo.mixins.json index 45f8185..31a398b 100644 --- a/src/main/resources/genyo.mixins.json +++ b/src/main/resources/genyo.mixins.json @@ -12,6 +12,7 @@ "PlayerUtilsMixin", "accessor.AccessorAnvilScreen", "accessor.AccessorBundlePacket", + "accessor.AccessorCrystalAura", "accessor.AccessorClientPlayerInteractionManager", "accessor.AccessorClientWorld", "accessor.AccessorGameOptions", @@ -25,7 +26,8 @@ "render.MixinEntityRenderer", "render.MixinRenderTickCounter", "render.MixinWorldRenderer", - "world.MixinClientWorld" + "world.MixinClientWorld", + "render.MixinWorldRendererBreaking" ], "injectors": { "defaultRequire": 1 From 5a2c653bbc67e9e71dced12e00f8e39c2c1e1397 Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 10:52:05 +0530 Subject: [PATCH 2/9] Fixed Base place - works with meteor or genyo Added Sound Toggles for all Sounds Auto Portal renamed to GenyoAutoPortal Added GenyoLogoutPoints Added GenyoNoMineAnimation Fixed GenyoSelfTrap.java head place Fixed GenyoMineESP.java to depend on packet instead of hand swing. --- src/main/java/com/genyo/Genyo.java | 2 + src/main/java/com/genyo/core/Core.java | 22 +- .../genyo/managers/combat/CombatManager.java | 6 +- .../mixin/accessor/AccessorCrystalAura.java | 11 + .../com/genyo/mixin/meteor/MixinWWidget.java | 16 +- .../render/MixinWorldRendererBreaking.java | 22 ++ .../com/genyo/systems/config/GenyoConfig.java | 121 ++++++++- .../systems/modules/combat/BasePlace.java | 21 +- .../systems/modules/combat/GenyoMineESP.java | 168 ++++++++---- .../systems/modules/misc/GenyoAutoPortal.java | 2 +- .../modules/visual/GenyoLogoutPoints.java | 247 ++++++++++++++++++ .../modules/visual/GenyoNoMineAnimation.java | 51 ++++ .../systems/modules/world/GenyoSelfTrap.java | 56 +++- src/main/resources/genyo.mixins.json | 4 +- 14 files changed, 665 insertions(+), 84 deletions(-) create mode 100644 src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java create mode 100644 src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java create mode 100644 src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java create mode 100644 src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index ff148ae..319f679 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -133,7 +133,9 @@ private void initSystems() { } private void initModules(Modules modules) { + modules.add(new GenyoLogoutPoints()); modules.add(new GenyoAutoEZ()); + modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); modules.add(new GenyoNuker()); diff --git a/src/main/java/com/genyo/core/Core.java b/src/main/java/com/genyo/core/Core.java index 2eb6dc9..81163fa 100644 --- a/src/main/java/com/genyo/core/Core.java +++ b/src/main/java/com/genyo/core/Core.java @@ -54,19 +54,26 @@ private float humanizeVolume(float min, float max) { @EventHandler public void onMessageReceive(ReceiveMessageEvent event) { String message = event.getMessage().getString().toLowerCase(); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg == null) return; if (message.contains("genyo") && !message.startsWith("§")) { - Managers.SOUND.playSound(VINE); + if (cfg.vineSound.get()) { + Managers.SOUND.playSound(VINE, cfg.vineVolume.get()); + } } else if (message.contains("verstappen")) { - Managers.SOUND.playSound(VERSTAPPEN); - } else if ((message.contains("nigga") || message.contains("nigger")) && - (GenyoConfig.get().blackPerson.get()) && GenyoConfig.get() != null) { + if (cfg.verstappenSound.get()) { + Managers.SOUND.playSound(VERSTAPPEN, cfg.verstappenVolume.get()); + } + } else if ((message.contains("nigga") || message.contains("nigger")) && cfg.blackPerson.get()) { if (soundTimer.passed(6000)) { Managers.SOUND.playSound(BLACK, 10); soundTimer.reset(); } } else if (message.contains("kiwi")) { - Managers.SOUND.playSound(KIWI); + if (cfg.kiwiSound.get()) { + Managers.SOUND.playSound(KIWI, cfg.kiwiVolume.get()); + } } } @@ -75,7 +82,10 @@ public void onPlayerRender(EntityAddedEvent event) { if (!(event.entity instanceof PlayerEntity player)) return; if (!Enemies.get().isEnemy(player)) return; - Managers.SOUND.playSound(HAMBURGER); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg != null && cfg.hamburgerSound.get()) { + Managers.SOUND.playSound(HAMBURGER, cfg.hamburgerVolume.get()); + } } } diff --git a/src/main/java/com/genyo/managers/combat/CombatManager.java b/src/main/java/com/genyo/managers/combat/CombatManager.java index 5fe767d..39bfeda 100644 --- a/src/main/java/com/genyo/managers/combat/CombatManager.java +++ b/src/main/java/com/genyo/managers/combat/CombatManager.java @@ -4,6 +4,7 @@ import com.genyo.events.UnderCombatEvent; import com.genyo.managers.Managers; import com.genyo.core.sound.SoundManager; +import com.genyo.systems.config.GenyoConfig; import com.genyo.utils.GenyoChatUtils; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.events.entity.player.AttackEntityEvent; @@ -61,7 +62,10 @@ public void onPacketReceive(PacketEvent.Receive event) { "\n\nReason: " + Formatting.GREEN + "ewrhjfkjerkjfhrejkgkregr" + Formatting.GRAY + "\nConclusion: " + Formatting.GREEN + "Skill issue. :("); - Managers.SOUND.playSound(SoundManager.SCREAM, 80); + GenyoConfig cfg = GenyoConfig.get(); + if (cfg != null && cfg.screamSound.get()) { + Managers.SOUND.playSound(SoundManager.SCREAM, cfg.screamVolume.get()); + } } } } diff --git a/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java b/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java new file mode 100644 index 0000000..07747bf --- /dev/null +++ b/src/main/java/com/genyo/mixin/accessor/AccessorCrystalAura.java @@ -0,0 +1,11 @@ +package com.genyo.mixin.accessor; + +import meteordevelopment.meteorclient.systems.modules.combat.CrystalAura; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CrystalAura.class) +public interface AccessorCrystalAura { + @Accessor("placing") + boolean isPlacing(); +} diff --git a/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java b/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java index 0a23237..d468849 100644 --- a/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java +++ b/src/main/java/com/genyo/mixin/meteor/MixinWWidget.java @@ -28,7 +28,7 @@ private void onMouseMoved(double mouseX, double mouseY, if (mouseOver && !genyo_wasOver) { GenyoConfig cfg = GenyoConfig.get(); - if (cfg != null && cfg.guiSounds.get()) { + if (cfg != null && cfg.hoverSoundEnabled.get()) { float vol = cfg.hoverVolume.get() / 100f; Managers.SOUND.playUISound(SoundManager.GUI_HOVER, vol, 1f); } @@ -44,14 +44,18 @@ private void onMouseClicked(Click click, boolean doubled, if (!mouseOver) return; GenyoConfig cfg = GenyoConfig.get(); - if (cfg == null || !cfg.guiSounds.get()) return; - - float vol = cfg.clickVolume.get() / 100f; + if (cfg == null) return; if (click.button() == 0) { - Managers.SOUND.playUISound(SoundManager.GUI_CLICK_LEFT, vol, 1f); + if (cfg.clickLeftSoundEnabled.get()) { + float vol = cfg.clickLeftVolume.get() / 100f; + Managers.SOUND.playUISound(SoundManager.GUI_CLICK_LEFT, vol, 1f); + } } else if (click.button() == 1) { - Managers.SOUND.playUISound(SoundManager.GUI_CLICK_RIGHT, vol, 1f); + if (cfg.clickRightSoundEnabled.get()) { + float vol = cfg.clickRightVolume.get() / 100f; + Managers.SOUND.playUISound(SoundManager.GUI_CLICK_RIGHT, vol, 1f); + } } } } diff --git a/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java b/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java new file mode 100644 index 0000000..c6b5f15 --- /dev/null +++ b/src/main/java/com/genyo/mixin/render/MixinWorldRendererBreaking.java @@ -0,0 +1,22 @@ +package com.genyo.mixin.render; + +import com.genyo.systems.modules.visual.GenyoNoMineAnimation; +import meteordevelopment.meteorclient.systems.modules.Modules; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.util.math.BlockPos; +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(WorldRenderer.class) +public abstract class MixinWorldRendererBreaking { + + @Inject(method = "setBlockBreakingInfo", at = @At("HEAD"), cancellable = true) + private void genyo$hookSetBlockBreakingInfo(int breakerId, BlockPos pos, int stage, CallbackInfo ci) { + GenyoNoMineAnimation module = Modules.get().get(GenyoNoMineAnimation.class); + if (module != null && module.shouldCancel(breakerId)) { + ci.cancel(); + } + } +} diff --git a/src/main/java/com/genyo/systems/config/GenyoConfig.java b/src/main/java/com/genyo/systems/config/GenyoConfig.java index 7ccd1bc..30dab78 100644 --- a/src/main/java/com/genyo/systems/config/GenyoConfig.java +++ b/src/main/java/com/genyo/systems/config/GenyoConfig.java @@ -33,11 +33,9 @@ public class GenyoConfig extends System { .build() ); - // In sgSounds group, add these three: - - public final Setting guiSounds = sgSounds.add(new BoolSetting.Builder() - .name("gui-sounds") - .description("Play sounds when hovering and clicking in Meteor's GUI.") + public final Setting hoverSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("hover-sound") + .description("Play a sound when hovering over a module in Meteor's GUI.") .defaultValue(true) .build() ); @@ -47,16 +45,39 @@ public class GenyoConfig extends System { .description("Volume of the hover sound.") .min(1).defaultValue(60).max(100) .sliderRange(1, 100) - .visible(guiSounds::get) + .visible(hoverSoundEnabled::get) + .build() + ); + + public final Setting clickLeftSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("click-left-sound") + .description("Play a sound when left-clicking a module in Meteor's GUI.") + .defaultValue(true) + .build() + ); + + public final Setting clickLeftVolume = sgSounds.add(new IntSetting.Builder() + .name("click-left-volume") + .description("Volume of the left-click sound.") + .min(1).defaultValue(80).max(100) + .sliderRange(1, 100) + .visible(clickLeftSoundEnabled::get) + .build() + ); + + public final Setting clickRightSoundEnabled = sgSounds.add(new BoolSetting.Builder() + .name("click-right-sound") + .description("Play a sound when right-clicking a module in Meteor's GUI.") + .defaultValue(true) .build() ); - public final Setting clickVolume = sgSounds.add(new IntSetting.Builder() - .name("click-volume") - .description("Volume of left/right click sounds.") + public final Setting clickRightVolume = sgSounds.add(new IntSetting.Builder() + .name("click-right-volume") + .description("Volume of the right-click sound.") .min(1).defaultValue(80).max(100) .sliderRange(1, 100) - .visible(guiSounds::get) + .visible(clickRightSoundEnabled::get) .build() ); @@ -83,6 +104,86 @@ public class GenyoConfig extends System { .build() ); + public final Setting vineSound = sgSounds.add(new BoolSetting.Builder() + .name("vine-sound") + .description("Play a sound when someone says 'genyo' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting vineVolume = sgSounds.add(new IntSetting.Builder() + .name("vine-volume") + .description("Volume of the vine sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(vineSound::get) + .build() + ); + + public final Setting verstappenSound = sgSounds.add(new BoolSetting.Builder() + .name("verstappen-sound") + .description("Play a sound when someone says 'verstappen' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting verstappenVolume = sgSounds.add(new IntSetting.Builder() + .name("verstappen-volume") + .description("Volume of the verstappen sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(verstappenSound::get) + .build() + ); + + public final Setting kiwiSound = sgSounds.add(new BoolSetting.Builder() + .name("kiwi-sound") + .description("Play a sound when someone says 'kiwi' in chat.") + .defaultValue(true) + .build() + ); + + public final Setting kiwiVolume = sgSounds.add(new IntSetting.Builder() + .name("kiwi-volume") + .description("Volume of the kiwi sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(kiwiSound::get) + .build() + ); + + public final Setting hamburgerSound = sgSounds.add(new BoolSetting.Builder() + .name("hamburger-sound") + .description("Play a sound when an enemy player renders in.") + .defaultValue(true) + .build() + ); + + public final Setting hamburgerVolume = sgSounds.add(new IntSetting.Builder() + .name("hamburger-volume") + .description("Volume of the hamburger sound.") + .min(1).defaultValue(100).max(100) + .sliderRange(1, 100) + .visible(hamburgerSound::get) + .build() + ); + + public final Setting screamSound = sgSounds.add(new BoolSetting.Builder() + .name("scream-sound") + .description("Play a sound when you die.") + .defaultValue(true) + .build() + ); + + public final Setting screamVolume = sgSounds.add(new IntSetting.Builder() + .name("scream-volume") + .description("Volume of the scream sound.") + .min(1).defaultValue(80).max(100) + .sliderRange(1, 100) + .visible(screamSound::get) + .build() + ); + // Visual public final Setting useGenyoSplashes = sgVisual.add(new BoolSetting.Builder() diff --git a/src/main/java/com/genyo/systems/modules/combat/BasePlace.java b/src/main/java/com/genyo/systems/modules/combat/BasePlace.java index a5d5e65..97217cb 100644 --- a/src/main/java/com/genyo/systems/modules/combat/BasePlace.java +++ b/src/main/java/com/genyo/systems/modules/combat/BasePlace.java @@ -3,6 +3,7 @@ import com.genyo.Genyo; import com.genyo.events.network.PlayerTickEvent; import com.genyo.managers.Managers; +import com.genyo.mixin.accessor.AccessorCrystalAura; import com.genyo.render.animation.Animation; import com.genyo.systems.modules.PlacerModule; import com.genyo.systems.settings.FloatSetting; @@ -126,7 +127,22 @@ public void onDeactivate() { @EventHandler public void onTick(PlayerTickEvent event) { - if (!Modules.get().isActive(GenyoAutoCrystal.class) || !Modules.get().isActive(CrystalAura.class) || Modules.get().get(GenyoAutoCrystal.class).isPlacing()) + boolean genyoActive = Modules.get().isActive(GenyoAutoCrystal.class); + boolean caActive = Modules.get().isActive(CrystalAura.class); + + // Neither aura running -> nothing for base-place to support + if (!genyoActive && !caActive) + { + return; + } + + // Don't interfere while the active aura is itself mid-placement + if (genyoActive && Modules.get().get(GenyoAutoCrystal.class).isPlacing()) + { + return; + } + + if (caActive && ((AccessorCrystalAura) Modules.get().get(CrystalAura.class)).isPlacing()) { return; } @@ -216,7 +232,8 @@ private BlockPos getCrystalBase(PlayerEntity player) continue; } - if (!Modules.get().get(GenyoAutoCrystal.class).isCrystalHitboxClear(pos)) + if (Modules.get().isActive(GenyoAutoCrystal.class) + && !Modules.get().get(GenyoAutoCrystal.class).isCrystalHitboxClear(pos)) { continue; } diff --git a/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java b/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java index 4e84eef..45e0d64 100644 --- a/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java +++ b/src/main/java/com/genyo/systems/modules/combat/GenyoMineESP.java @@ -17,14 +17,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import org.joml.Vector3d; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class GenyoMineESP extends Module { @@ -47,7 +44,7 @@ public enum RenderMode { private final Setting syncDoubleMine = sgGeneral.add(new BoolSetting.Builder() .name("sync-double-mine") - .description("Próbálja meg kitalálni és szinkronizálni a második bányászott blokkot (Heurisztikus).") + .description("Jelzi, ha ugyanaz a játékos egyszerre több blokkot is bányászik (szerver csomagok alapján).") .defaultValue(true) .build() ); @@ -59,6 +56,13 @@ public enum RenderMode { .build() ); + private final Setting showOwnMining = sgGeneral.add(new BoolSetting.Builder() + .name("show-own-mining") + .description("Az ESP a saját bányászásunkat is mutassa.") + .defaultValue(false) + .build() + ); + private final Setting customFont = sgGeneral.add(new BoolSetting.Builder() .name("custom-font") .description("Meteor egyedi betűtípusának használata.") @@ -79,6 +83,19 @@ public enum RenderMode { .build() ); + private final Setting doubleMineSideColor = sgColors.add(new ColorSetting.Builder() + .name("double-mine-side-color") + .description("A doboz színe, ha a játékos egyszerre több blokkot bányászik.") + .defaultValue(new SettingColor(255, 165, 0, 100)) + .build() + ); + + private final Setting doubleMineLineColor = sgColors.add(new ColorSetting.Builder() + .name("double-mine-line-color") + .defaultValue(new SettingColor(255, 165, 0, 255)) + .build() + ); + private final Setting textColor = sgColors.add(new ColorSetting.Builder() .name("text-color") .defaultValue(new SettingColor(255, 255, 255, 255)) @@ -110,30 +127,22 @@ public enum RenderMode { ); private final Map blocks = new ConcurrentHashMap<>(); - private final Map suspectedMines = new ConcurrentHashMap<>(); private final Map lastBrokenBlocks = new ConcurrentHashMap<>(); - private final Set swingingEntities = ConcurrentHashMap.newKeySet(); + private BlockPos selfBreakingPos = null; public GenyoMineESP() { - super(Genyo.COMBAT, "mine-esp", "Fejlett ESP Liquid effekttel, Double Mine és Rebreak szinkronnal."); + super(Genyo.COMBAT, "genyo-mine-esp", "Fejlett ESP Liquid effekttel, Double Mine és Rebreak szinkronnal."); } @Override public void onDeactivate() { blocks.clear(); - suspectedMines.clear(); lastBrokenBlocks.clear(); - swingingEntities.clear(); + selfBreakingPos = null; } @EventHandler private void onReceivePacket(PacketEvent.Receive event) { - if (event.packet instanceof EntityAnimationS2CPacket animPacket) { - if (animPacket.getAnimationId() == 0 || animPacket.getAnimationId() == 3) { - swingingEntities.add(animPacket.getEntityId()); - } - } - if (event.packet instanceof BlockBreakingProgressS2CPacket packet) { BlockPos pos = packet.getPos(); int stage = packet.getProgress(); @@ -157,23 +166,7 @@ private void onReceivePacket(PacketEvent.Receive event) { @EventHandler private void onTick(TickEvent.Pre event) { - if (syncDoubleMine.get()) { - for (int entityId : swingingEntities) { - Entity entity = mc.world.getEntityById(entityId); - if (entity instanceof PlayerEntity && entity != mc.player) { - HitResult hit = entity.raycast(6.0, 1.0f, false); - if (hit instanceof BlockHitResult blockHit) { - BlockPos hitPos = blockHit.getBlockPos(); - if (!mc.world.getBlockState(hitPos).isAir()) { - suspectedMines.put(entityId, hitPos); - } - } - } - } - } - swingingEntities.clear(); - - suspectedMines.entrySet().removeIf(entry -> mc.world.getBlockState(entry.getValue()).isAir()); + updateOwnMining(); blocks.entrySet().removeIf(entry -> { MineData data = entry.getValue(); @@ -183,6 +176,68 @@ private void onTick(TickEvent.Pre event) { data.renderProgress += (target - data.renderProgress) * 0.15; return false; }); + + if (syncDoubleMine.get()) { + Map activeCounts = new ConcurrentHashMap<>(); + for (MineData data : blocks.values()) { + activeCounts.merge(data.entityId, 1, Integer::sum); + } + for (MineData data : blocks.values()) { + data.isDoubleMine = activeCounts.getOrDefault(data.entityId, 0) > 1; + } + } else { + for (MineData data : blocks.values()) { + data.isDoubleMine = false; + } + } + } + + private void updateOwnMining() { + if (mc.player == null || mc.interactionManager == null || !showOwnMining.get()) { + if (selfBreakingPos != null) { + blocks.remove(selfBreakingPos); + selfBreakingPos = null; + } + return; + } + + boolean breakingNow = mc.interactionManager.isBreakingBlock() && mc.crosshairTarget instanceof BlockHitResult; + + if (!breakingNow) { + if (selfBreakingPos != null) { + // If the block wasn't actually mined (i.e. we aborted), remove it immediately + // instead of waiting for the timeout. A finished block is already air and gets + // cleaned up by the removeIf air-check right after this runs. + if (!mc.world.getBlockState(selfBreakingPos).isAir()) { + blocks.remove(selfBreakingPos); + } + selfBreakingPos = null; + } + return; + } + + BlockHitResult hit = (BlockHitResult) mc.crosshairTarget; + BlockPos pos = hit.getBlockPos(); + int entityId = mc.player.getId(); + + int stage = mc.interactionManager.getBlockBreakingProgress(); + if (stage < 0) { + stage = 0; + } + + if (selfBreakingPos != null && !selfBreakingPos.equals(pos)) { + blocks.remove(selfBreakingPos); + } + + MineData data = blocks.get(pos); + if (data == null) { + boolean isRebreak = pos.equals(lastBrokenBlocks.get(entityId)); + blocks.put(pos, new MineData(pos, entityId, stage, isRebreak)); + } else { + data.targetStage = stage; + data.timer = 0; + } + selfBreakingPos = pos; } @EventHandler @@ -191,12 +246,6 @@ private void onRender3D(Render3DEvent event) { for (MineData data : blocks.values()) { renderBox(event, data.pos, data); - if (syncDoubleMine.get()) { - BlockPos suspected = suspectedMines.get(data.entityId); - if (suspected != null && !suspected.equals(data.pos)) { - renderBox(event, suspected, data); - } - } } } @@ -206,20 +255,24 @@ private void onRender2D(Render2DEvent event) { for (MineData data : blocks.values()) { renderText(event, data.pos, data); - if (syncDoubleMine.get()) { - BlockPos suspected = suspectedMines.get(data.entityId); - if (suspected != null && !suspected.equals(data.pos)) { - renderText(event, suspected, data); - } - } } } private void renderBox(Render3DEvent event, BlockPos pos, MineData data) { if (mc.player.squaredDistanceTo(pos.toCenterPos()) > radius.get() * radius.get()) return; - Color currentSide = data.isRebreak ? rebreakSideColor.get() : lerpColor(sideColorStart.get(), sideColorEnd.get(), data.renderProgress); - Color currentLine = data.isRebreak ? rebreakLineColor.get() : lerpColor(lineColorStart.get(), lineColorEnd.get(), data.renderProgress); + Color currentSide; + Color currentLine; + if (data.isRebreak) { + currentSide = rebreakSideColor.get(); + currentLine = rebreakLineColor.get(); + } else if (data.isDoubleMine) { + currentSide = doubleMineSideColor.get(); + currentLine = doubleMineLineColor.get(); + } else { + currentSide = lerpColor(sideColorStart.get(), sideColorEnd.get(), data.renderProgress); + currentLine = lerpColor(lineColorStart.get(), lineColorEnd.get(), data.renderProgress); + } if (renderMode.get() == RenderMode.Liquid) { double time = System.currentTimeMillis() / 200.0; @@ -261,13 +314,22 @@ private void renderText(Render2DEvent event, BlockPos pos, MineData data) { Vector3d pos2d = new Vector3d(pos3d); if (NametagUtils.to2D(pos2d, 1.5)) { + String tag = null; + Color tagColor = null; + if (data.isRebreak) { + tag = "Rebreak"; + tagColor = rebreakLineColor.get(); + } else if (data.isDoubleMine) { + tag = "Double Mine"; + tagColor = doubleMineLineColor.get(); + } + if (customFont.get()) { NametagUtils.begin(pos3d); TextRenderer.get().begin(1.0, false, true); TextRenderer.get().render(text, -TextRenderer.get().getWidth(text) / 2.0, 0, textColor.get(), true); - if (data.isRebreak) { - String rb = "Rebreak"; - TextRenderer.get().render(rb, -TextRenderer.get().getWidth(rb) / 2.0, 12, rebreakLineColor.get(), true); + if (tag != null) { + TextRenderer.get().render(tag, -TextRenderer.get().getWidth(tag) / 2.0, 12, tagColor, true); } TextRenderer.get().end(); NametagUtils.end(); @@ -276,10 +338,9 @@ private void renderText(Render2DEvent event, BlockPos pos, MineData data) { int x = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(text) / 2); int y = (int) (pos2d.y / scale); event.drawContext.drawTextWithShadow(mc.textRenderer, text, x, y, textColor.get().getPacked()); - if (data.isRebreak) { - String rb = "Rebreak"; - int rbX = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(rb) / 2); - event.drawContext.drawTextWithShadow(mc.textRenderer, rb, rbX, y + 10, rebreakLineColor.get().getPacked()); + if (tag != null) { + int tagX = (int) (pos2d.x / scale) - (mc.textRenderer.getWidth(tag) / 2); + event.drawContext.drawTextWithShadow(mc.textRenderer, tag, tagX, y + 10, tagColor.getPacked()); } } } @@ -300,6 +361,7 @@ private static class MineData { public double renderProgress; public int timer; public boolean isRebreak; + public boolean isDoubleMine; public MineData(BlockPos pos, int entityId, int stage, boolean isRebreak) { this.pos = pos; diff --git a/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java b/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java index d6fe582..a9ba699 100644 --- a/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java +++ b/src/main/java/com/genyo/systems/modules/misc/GenyoAutoPortal.java @@ -82,7 +82,7 @@ public class GenyoAutoPortal extends Module { ); public GenyoAutoPortal() { - super(Genyo.MISC, "auto-portal", "Builds a Nether portal with Delay, Auto-Refill, and Hotbar Cleanup."); + super(Genyo.MISC, "genyo-auto-portal", "Builds a Nether portal with Delay, Auto-Refill, and Hotbar Cleanup."); } private final List frameBlocks = new ArrayList<>(); diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java new file mode 100644 index 0000000..139806e --- /dev/null +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutPoints.java @@ -0,0 +1,247 @@ +package com.genyo.systems.modules.visual; + +import com.genyo.Genyo; +import com.genyo.render.animation.Animation; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.render.Render2DEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.renderer.text.TextRenderer; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.render.NametagUtils; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import org.joml.Vector3d; + +import java.text.DecimalFormat; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class GenyoLogoutPoints extends Module { + + private static final DecimalFormat DECIMAL = new DecimalFormat("#.#"); + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting showDistance = sgGeneral.add(new BoolSetting.Builder() + .name("distance") + .description("Shows distance from the logout.") + .defaultValue(false) + .build() + ); + + private final Setting showTimePassed = sgGeneral.add(new BoolSetting.Builder() + .name("time-passed") + .description("Shows time passed since logout.") + .defaultValue(false) + .build() + ); + + private final Setting fadeTime = sgGeneral.add(new IntSetting.Builder() + .name("fade-time") + .description("How long the fade in/out animation takes, in milliseconds.") + .min(0) + .defaultValue(500) + .max(2000) + .build() + ); + + private final Setting boxColor = sgGeneral.add(new ColorSetting.Builder() + .name("box-color") + .description("Color of the logout marker outline.") + .defaultValue(new SettingColor(255, 255, 255, 255)) + .build() + ); + + private final Setting textColor = sgGeneral.add(new ColorSetting.Builder() + .name("text-color") + .description("Color of the logout tag text.") + .defaultValue(new SettingColor(255, 255, 255, 255)) + .build() + ); + + private final Map onlinePlayers = new ConcurrentHashMap<>(); + private final Map offlinePlayers = new ConcurrentHashMap<>(); + + public GenyoLogoutPoints() { + super(Genyo.VISUAL, "genyo-logout-points", "Marks nearby logouts."); + } + + @Override + public void onDeactivate() { + onlinePlayers.clear(); + offlinePlayers.clear(); + } + + @EventHandler + public void onTick(TickEvent.Post event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (PlayerEntity player : mc.world.getPlayers()) { + if (player != null && player.getGameProfile() != null && !player.equals(mc.player)) { + onlinePlayers.put(player.getGameProfile().id(), new LogoutData(player, fadeTime.get())); + } + } + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) { + if (mc.player == null || mc.world == null) { + return; + } + + if (event.packet instanceof PlayerListS2CPacket packet + && packet.getActions().contains(PlayerListS2CPacket.Action.ADD_PLAYER)) { + for (PlayerListS2CPacket.Entry entry : packet.getPlayerAdditionEntries()) { + LogoutData data = offlinePlayers.get(entry.profile().id()); + if (data != null) { + data.setState(false); + } + } + + onlinePlayers.clear(); + } else if (event.packet instanceof PlayerRemoveS2CPacket packet) { + List profileIds = packet.profileIds(); + for (UUID uuid : profileIds) { + LogoutData data = onlinePlayers.get(uuid); + if (data == null) { + continue; + } + + if (!offlinePlayers.containsKey(uuid)) { + offlinePlayers.put(uuid, data); + data.setState(true); + } + } + + onlinePlayers.clear(); + } + } + + @EventHandler + public void onRender3D(Render3DEvent event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (Map.Entry set : offlinePlayers.entrySet()) { + LogoutData data = set.getValue(); + if (data == null) { + continue; + } + + double factor = data.getAnimation().getFactor(); + if (!data.getAnimation().getState() && factor <= 0.01) { + offlinePlayers.remove(set.getKey()); + continue; + } + + PlayerEntity offlinePlayer = data.getOfflinePlayer(); + Box box = offlinePlayer.getBoundingBox(); + + Color lineColor = boxColor.get().a((int) (boxColor.get().a * factor)); + Color sideColor = lineColor.a((int) (lineColor.a * 0.4)); + + event.renderer.box( + box.minX, box.minY, box.minZ, + box.maxX, box.maxY, box.maxZ, + sideColor, lineColor, ShapeMode.Lines, 0 + ); + } + } + + @EventHandler + public void onRender2D(Render2DEvent event) { + if (mc.player == null || mc.world == null) { + return; + } + + for (LogoutData data : offlinePlayers.values()) { + double factor = data.getAnimation().getFactor(); + if (factor <= 0.01) { + continue; + } + + PlayerEntity offlinePlayer = data.getOfflinePlayer(); + Box box = offlinePlayer.getBoundingBox(); + + StringBuilder logoutTag = new StringBuilder(offlinePlayer.getName().getString() + "'s Logout"); + + boolean hasExtraInfo = false; + if (showDistance.get()) { + hasExtraInfo = true; + double dist = Math.sqrt(mc.player.squaredDistanceTo(offlinePlayer.getEntityPos())); + logoutTag.append(" - ").append(DECIMAL.format(dist)).append("m"); + } + + if (showTimePassed.get()) { + if (!hasExtraInfo) { + logoutTag.append(" -"); + } + + long seconds = (System.currentTimeMillis() - data.getLogoutTime()) / 1000; + if (seconds < 60) { + logoutTag.append(" ").append(seconds).append("s"); + } else { + long minutes = seconds / 60; + logoutTag.append(" ").append(minutes).append("min"); + } + } + + Vec3d center = box.getCenter(); + Vector3d pos3d = new Vector3d(center.x, box.maxY + 0.2, center.z); + Vector3d pos2d = new Vector3d(pos3d); + + if (NametagUtils.to2D(pos2d, 1.5)) { + Color currentTextColor = textColor.get().a((int) (textColor.get().a * factor)); + String tag = logoutTag.toString(); + + NametagUtils.begin(pos3d); + TextRenderer.get().begin(1.0, false, true); + TextRenderer.get().render(tag, -TextRenderer.get().getWidth(tag) / 2.0, 0, currentTextColor, true); + TextRenderer.get().end(); + NametagUtils.end(); + } + } + } + + private static class LogoutData { + private final PlayerEntity offlinePlayer; + private final long logoutTime; + private final Animation animation; + + public LogoutData(PlayerEntity offlinePlayer, float fadeLength) { + this.offlinePlayer = offlinePlayer; + this.logoutTime = System.currentTimeMillis(); + this.animation = new Animation(false, fadeLength); + } + + public PlayerEntity getOfflinePlayer() { + return offlinePlayer; + } + + public long getLogoutTime() { + return logoutTime; + } + + public Animation getAnimation() { + return animation; + } + + public void setState(boolean state) { + this.animation.setState(state); + } + } +} diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java b/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java new file mode 100644 index 0000000..f56d5d4 --- /dev/null +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoNoMineAnimation.java @@ -0,0 +1,51 @@ +package com.genyo.systems.modules.visual; + + + +import com.genyo.Genyo; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; + +public class GenyoNoMineAnimation extends Module { + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + public final Setting mode = sgGeneral.add(new EnumSetting.Builder() + .name("mode") + .description("Whose block-breaking animation to hide.") + .defaultValue(Mode.Everyone) + .build() + ); + + private final Setting hideParticles = sgGeneral.add(new BoolSetting.Builder() + .name("hide-particles") + .description("Also hides the block-breaking particles.") + .defaultValue(true) + .build() + ); + + public GenyoNoMineAnimation() { + super(Genyo.VISUAL, "genyo-no-mine-animation", "Hides the block-breaking (crack) animation."); + } + + // Used by the mixin to decide whether to cancel a given breaking-info update. + public boolean shouldCancel(int breakerId) { + if (!isActive()) return false; + + boolean isSelf = mc.player != null && breakerId == mc.player.getId(); + + return switch (mode.get()) { + case Everyone -> true; + case OthersOnly -> !isSelf; + case SelfOnly -> isSelf; + }; + } + + public boolean hideParticles() { + return isActive() && hideParticles.get(); + } + + public enum Mode { + Everyone, OthersOnly, SelfOnly + } +} diff --git a/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java b/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java index 15ab32a..05aba73 100644 --- a/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java +++ b/src/main/java/com/genyo/systems/modules/world/GenyoSelfTrap.java @@ -15,6 +15,7 @@ import meteordevelopment.meteorclient.renderer.ShapeMode; import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.player.AirPlace; import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; @@ -105,7 +106,14 @@ public GenyoSelfTrap() { private final Setting head = sgGeneral.add(new BoolSetting.Builder() .name("Cover Head") - .description("Doesn't work rn") + .description("Places a block above the player's head.") + .defaultValue(false) + .build() + ); + + private final Setting antiStep = sgGeneral.add(new BoolSetting.Builder() + .name("Prevent Step") + .description("Prevents the player from stepping out of the trap") .defaultValue(false) .build() ); @@ -487,10 +495,50 @@ public List getSurround(PlayerEntity player) } } - /*if (AirPlaceModule.getInstance().isEnabled() && head.get()) + if (head.get()) { - surroundBlocks.add(mc.player.getBlockPos().up(2)); - }*/ + boolean supported = false; + final List headBlocks = new ArrayList<>(); + for (BlockPos pos : playerBlocks) + { + BlockPos headPos = pos.offset(Direction.UP, 2); + if (!mc.world.getBlockState(headPos).isReplaceable()) + { + supported = true; + } + headBlocks.add(headPos); + if (antiStep.get()) + { + BlockPos antiStepPos = pos.offset(Direction.UP, 3); + headBlocks.add(antiStepPos); + } + } + if (!Modules.get().isActive(AirPlace.class)) + { + BlockPos supportingPos = null; + double min = Double.MAX_VALUE; + for (BlockPos pos : surroundBlocks) + { + BlockPos pos1 = pos.offset(Direction.UP, 2); + if (!mc.world.getBlockState(pos1).isReplaceable()) + { + supported = true; + break; + } + double dist = mc.player.squaredDistanceTo(pos1.toCenterPos()); + if (dist < min) + { + supportingPos = pos1; + min = dist; + } + } + if (supportingPos != null && !supported) + { + surroundBlocks.add(supportingPos); + } + } + surroundBlocks.addAll(headBlocks); + } return surroundBlocks; } diff --git a/src/main/resources/genyo.mixins.json b/src/main/resources/genyo.mixins.json index 45f8185..31a398b 100644 --- a/src/main/resources/genyo.mixins.json +++ b/src/main/resources/genyo.mixins.json @@ -12,6 +12,7 @@ "PlayerUtilsMixin", "accessor.AccessorAnvilScreen", "accessor.AccessorBundlePacket", + "accessor.AccessorCrystalAura", "accessor.AccessorClientPlayerInteractionManager", "accessor.AccessorClientWorld", "accessor.AccessorGameOptions", @@ -25,7 +26,8 @@ "render.MixinEntityRenderer", "render.MixinRenderTickCounter", "render.MixinWorldRenderer", - "world.MixinClientWorld" + "world.MixinClientWorld", + "render.MixinWorldRendererBreaking" ], "injectors": { "defaultRequire": 1 From 35c2b118a276532b70cc92b484c36b1928863de4 Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 10:59:26 +0530 Subject: [PATCH 3/9] Fixed Base place - works with meteor or genyo Added Sound Toggles for all Sounds Auto Portal renamed to GenyoAutoPortal Added GenyoLogoutPoints Added GenyoNoMineAnimation Fixed GenyoSelfTrap.java head place Fixed GenyoMineESP.java to depend on packet instead of hand swing. --- src/main/java/com/genyo/Genyo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index 319f679..317c587 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -133,9 +133,9 @@ private void initSystems() { } private void initModules(Modules modules) { - modules.add(new GenyoLogoutPoints()); modules.add(new GenyoAutoEZ()); modules.add(new GenyoNoMineAnimation()); + modules.add(new GenyoLogoutPoints()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); modules.add(new GenyoNuker()); From 372e192bd82394ab1c8c520ab6b268364c3236b1 Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 11:00:27 +0530 Subject: [PATCH 4/9] Fixed Base place - works with meteor or genyo Added Sound Toggles for all Sounds Auto Portal renamed to GenyoAutoPortal Added GenyoLogoutPoints Added GenyoNoMineAnimation Fixed GenyoSelfTrap.java head place Fixed GenyoMineESP.java to depend on packet instead of hand swing. --- src/main/java/com/genyo/Genyo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index 317c587..2e81dbe 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -134,8 +134,8 @@ private void initSystems() { private void initModules(Modules modules) { modules.add(new GenyoAutoEZ()); - modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoLogoutPoints()); + modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); modules.add(new GenyoNuker()); From eeae748a4c8ef936c9f81c26a69b304adb631030 Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 11:06:55 +0530 Subject: [PATCH 5/9] Fixed Base place - works with meteor or genyo Added Sound Toggles for all Sounds Auto Portal renamed to GenyoAutoPortal Added GenyoLogoutPoints Added GenyoNoMineAnimation Fixed GenyoSelfTrap.java head place Fixed GenyoMineESP.java to depend on packet instead of hand swing. --- src/main/java/com/genyo/Genyo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index 2e81dbe..51e68f2 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -134,7 +134,7 @@ private void initSystems() { private void initModules(Modules modules) { modules.add(new GenyoAutoEZ()); - modules.add(new GenyoLogoutPoints()); + // modules.add(new GenyoLogoutPoints()); modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); From b37114bf7cbb88b1e7ea0faaebe18d9ec9a8d8df Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 13:14:19 +0530 Subject: [PATCH 6/9] Fucking Logout Spots + AUtotrapLogoutSpots --- src/main/java/com/genyo/Genyo.java | 1 + .../mixin/accessor/AccessorLogoutSpots.java | 13 ++ .../player/MixinLivingEntityRenderer.java | 25 +++ .../genyo/render/FrozenPlayerRenderState.java | 78 ++++++++ .../genyo/render/PlayerWireframeRenderer.java | 61 ++++++ .../com/genyo/render/RenderStateCache.java | 34 ++++ .../systems/modules/combat/GenyoAutoTrap.java | 94 ++++++++- .../modules/visual/GenyoLogoutSpots.java | 186 ++++++++++++++++++ src/main/resources/genyo.mixins.json | 1 + 9 files changed, 488 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/genyo/mixin/accessor/AccessorLogoutSpots.java create mode 100644 src/main/java/com/genyo/mixin/entity/player/MixinLivingEntityRenderer.java create mode 100644 src/main/java/com/genyo/render/FrozenPlayerRenderState.java create mode 100644 src/main/java/com/genyo/render/PlayerWireframeRenderer.java create mode 100644 src/main/java/com/genyo/render/RenderStateCache.java create mode 100644 src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java diff --git a/src/main/java/com/genyo/Genyo.java b/src/main/java/com/genyo/Genyo.java index 51e68f2..bb8626c 100644 --- a/src/main/java/com/genyo/Genyo.java +++ b/src/main/java/com/genyo/Genyo.java @@ -135,6 +135,7 @@ private void initSystems() { private void initModules(Modules modules) { modules.add(new GenyoAutoEZ()); // modules.add(new GenyoLogoutPoints()); + modules.add(new GenyoLogoutSpots()); modules.add(new GenyoNoMineAnimation()); modules.add(new GenyoAutoPortal()); modules.add(new GenyoMineESP()); diff --git a/src/main/java/com/genyo/mixin/accessor/AccessorLogoutSpots.java b/src/main/java/com/genyo/mixin/accessor/AccessorLogoutSpots.java new file mode 100644 index 0000000..d4daab5 --- /dev/null +++ b/src/main/java/com/genyo/mixin/accessor/AccessorLogoutSpots.java @@ -0,0 +1,13 @@ +package com.genyo.mixin.accessor; + +import meteordevelopment.meteorclient.systems.modules.render.LogoutSpots; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(LogoutSpots.class) +public interface AccessorLogoutSpots { + @Accessor("players") + List getPlayers(); +} diff --git a/src/main/java/com/genyo/mixin/entity/player/MixinLivingEntityRenderer.java b/src/main/java/com/genyo/mixin/entity/player/MixinLivingEntityRenderer.java new file mode 100644 index 0000000..ee26ef7 --- /dev/null +++ b/src/main/java/com/genyo/mixin/entity/player/MixinLivingEntityRenderer.java @@ -0,0 +1,25 @@ +package com.genyo.mixin.entity.player; + + +import com.genyo.render.FrozenPlayerRenderState; +import com.genyo.render.RenderStateCache; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +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(LivingEntityRenderer.class) +public class MixinLivingEntityRenderer { + + @Inject(method = "updateRenderState(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;F)V", at = @At("TAIL")) + private void genyo$captureState(LivingEntity entity, LivingEntityRenderState state, float tickDelta, CallbackInfo ci) { + if (entity instanceof PlayerEntity player && state instanceof PlayerEntityRenderState playerState) { + RenderStateCache.put(player.getUuid(), FrozenPlayerRenderState.copyOf(playerState)); + } + } +} diff --git a/src/main/java/com/genyo/render/FrozenPlayerRenderState.java b/src/main/java/com/genyo/render/FrozenPlayerRenderState.java new file mode 100644 index 0000000..e92ac76 --- /dev/null +++ b/src/main/java/com/genyo/render/FrozenPlayerRenderState.java @@ -0,0 +1,78 @@ +package com.genyo.render; + +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; + +/** A frozen, non-mutating copy of a PlayerEntityRenderState, captured at logout. */ +public class FrozenPlayerRenderState extends PlayerEntityRenderState { + + public static FrozenPlayerRenderState copyOf(PlayerEntityRenderState src) { + FrozenPlayerRenderState f = new FrozenPlayerRenderState(); + + // EntityRenderState + f.entityType = src.entityType; + f.x = src.x; f.y = src.y; f.z = src.z; + f.age = src.age; + f.width = src.width; f.height = src.height; + f.standingEyeHeight = src.standingEyeHeight; + f.invisible = src.invisible; + f.sneaking = src.sneaking; + f.onFire = src.onFire; + f.light = src.light; + f.outlineColor = src.outlineColor; + + // LivingEntityRenderState + f.bodyYaw = src.bodyYaw; + f.relativeHeadYaw = src.relativeHeadYaw; + f.pitch = src.pitch; + f.deathTime = src.deathTime; + f.limbSwingAnimationProgress = src.limbSwingAnimationProgress; + f.limbSwingAmplitude = src.limbSwingAmplitude; + f.baseScale = src.baseScale; + f.ageScale = src.ageScale; + f.flipUpsideDown = src.flipUpsideDown; + f.shaking = src.shaking; + f.baby = src.baby; + f.touchingWater = src.touchingWater; + f.usingRiptide = src.usingRiptide; + f.hurt = src.hurt; + f.pose = src.pose; + + // ArmedEntityRenderState + f.mainArm = src.mainArm; + f.rightArmPose = src.rightArmPose; + f.leftArmPose = src.leftArmPose; + f.rightHandItem = src.rightHandItem.copy(); + f.leftHandItem = src.leftHandItem.copy(); + f.swingAnimationType = src.swingAnimationType; + f.handSwingProgress = src.handSwingProgress; // frozen value; won't animate further, which is intended + + // BipedEntityRenderState + f.leaningPitch = src.leaningPitch; + f.limbAmplitudeInverse = src.limbAmplitudeInverse; + f.crossbowPullTime = src.crossbowPullTime; + f.itemUseTime = src.itemUseTime; + f.preferredArm = src.preferredArm; + f.activeHand = src.activeHand; + f.isInSneakingPose = src.isInSneakingPose; + f.isGliding = src.isGliding; + f.isSwimming = src.isSwimming; + f.hasVehicle = src.hasVehicle; + f.isUsingItem = src.isUsingItem; + f.equippedHeadStack = src.equippedHeadStack.copy(); + f.equippedChestStack = src.equippedChestStack.copy(); + f.equippedLegsStack = src.equippedLegsStack.copy(); + f.equippedFeetStack = src.equippedFeetStack.copy(); + + // PlayerEntityRenderState + f.skinTextures = src.skinTextures; + f.spectator = src.spectator; + f.hatVisible = src.hatVisible; + f.jacketVisible = src.jacketVisible; + f.leftPantsLegVisible = src.leftPantsLegVisible; + f.rightPantsLegVisible = src.rightPantsLegVisible; + f.leftSleeveVisible = src.leftSleeveVisible; + f.rightSleeveVisible = src.rightSleeveVisible; + + return f; + } +} diff --git a/src/main/java/com/genyo/render/PlayerWireframeRenderer.java b/src/main/java/com/genyo/render/PlayerWireframeRenderer.java new file mode 100644 index 0000000..eaca883 --- /dev/null +++ b/src/main/java/com/genyo/render/PlayerWireframeRenderer.java @@ -0,0 +1,61 @@ +package com.genyo.render; + +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.utils.render.color.Color; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.RotationAxis; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class PlayerWireframeRenderer { + + private static final int[][] EDGES = { + {0, 1}, {1, 2}, {2, 3}, {3, 0}, // bottom face + {4, 5}, {5, 6}, {6, 7}, {7, 4}, // top face + {0, 4}, {1, 5}, {2, 6}, {3, 7} // verticals connecting bottom to top + }; + + public static void render(Render3DEvent event, ModelPart root, + double originX, double originY, double originZ, + float bodyYaw, Color color) { + MatrixStack matrices = new MatrixStack(); + + // Mirrors LivingEntityRenderer.render(): body-yaw rotation, then the + // model-space -> world-space flip and vertical offset used for every + // biped model render. + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F - bodyYaw)); + matrices.scale(-1.0F, -1.0F, 1.0F); + matrices.translate(0.0F, -1.501F, 0.0F); + + root.forEachCuboid(matrices, (entry, path, index, cuboid) -> { + Matrix4f mat = entry.getPositionMatrix(); + + Vector3f[] corners = new Vector3f[] { + new Vector3f(cuboid.minX / 16f, cuboid.minY / 16f, cuboid.minZ / 16f), + new Vector3f(cuboid.maxX / 16f, cuboid.minY / 16f, cuboid.minZ / 16f), + new Vector3f(cuboid.maxX / 16f, cuboid.minY / 16f, cuboid.maxZ / 16f), + new Vector3f(cuboid.minX / 16f, cuboid.minY / 16f, cuboid.maxZ / 16f), + new Vector3f(cuboid.minX / 16f, cuboid.maxY / 16f, cuboid.minZ / 16f), + new Vector3f(cuboid.maxX / 16f, cuboid.maxY / 16f, cuboid.minZ / 16f), + new Vector3f(cuboid.maxX / 16f, cuboid.maxY / 16f, cuboid.maxZ / 16f), + new Vector3f(cuboid.minX / 16f, cuboid.maxY / 16f, cuboid.maxZ / 16f), + }; + + for (Vector3f corner : corners) { + mat.transformPosition(corner); + } + + for (int[] edge : EDGES) { + Vector3f a = corners[edge[0]]; + Vector3f b = corners[edge[1]]; + + event.renderer.line( + originX + a.x, originY + a.y, originZ + a.z, + originX + b.x, originY + b.y, originZ + b.z, + color + ); + } + }); + } +} diff --git a/src/main/java/com/genyo/render/RenderStateCache.java b/src/main/java/com/genyo/render/RenderStateCache.java new file mode 100644 index 0000000..0e283b2 --- /dev/null +++ b/src/main/java/com/genyo/render/RenderStateCache.java @@ -0,0 +1,34 @@ +package com.genyo.render; + +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.events.game.GameLeftEvent; +import meteordevelopment.orbit.EventHandler; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class RenderStateCache { + private static final Map cache = new ConcurrentHashMap<>(); + + static { + MeteorClient.EVENT_BUS.subscribe(new Object() { + @EventHandler + private void onGameLeft(GameLeftEvent event) { + cache.clear(); + } + }); + } + + public static void put(UUID uuid, FrozenPlayerRenderState state) { + cache.put(uuid, state); + } + + public static FrozenPlayerRenderState freeze(UUID uuid) { + return cache.get(uuid); + } + + public static void clear(UUID uuid) { + cache.remove(uuid); + } +} diff --git a/src/main/java/com/genyo/systems/modules/combat/GenyoAutoTrap.java b/src/main/java/com/genyo/systems/modules/combat/GenyoAutoTrap.java index c8e701d..d6709d1 100644 --- a/src/main/java/com/genyo/systems/modules/combat/GenyoAutoTrap.java +++ b/src/main/java/com/genyo/systems/modules/combat/GenyoAutoTrap.java @@ -4,6 +4,7 @@ import com.genyo.events.network.PlayerTickEvent; import com.genyo.managers.Managers; import com.genyo.systems.modules.PlacerModule; +import com.genyo.systems.modules.visual.GenyoLogoutSpots; import com.genyo.render.animation.Animation; import com.genyo.systems.settings.FloatSetting; import com.genyo.utils.math.GPositionUtils; @@ -122,6 +123,13 @@ public GenyoAutoTrap() { .build() ); + private final Setting useLogoutSpotsConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Use Logout Spots") + .description("Falls back to trapping a frozen logout spot if no live target is found") + .defaultValue(true) + .build() + ); + // Render private final Setting renderConfig = sgRender.add(new BoolSetting.Builder() @@ -182,16 +190,45 @@ public void onPlayerTick(PlayerTickEvent event) placements.clear(); return; } + PlayerEntity trapTarget = getTrapTarget(); - if (trapTarget == null) + BlockPos targetBlockPos; + + if (trapTarget != null) + { + targetBlockPos = GPositionUtils.getRoundedBlockPos(trapTarget.getX(), trapTarget.getY(), trapTarget.getZ()); + surround = getSurround(targetBlockPos, trapTarget.getBoundingBox()); + } + else if (useLogoutSpotsConfig.get()) + { + GenyoLogoutSpots.Spot logout = getNearestLogoutSpot(); + if (logout == null) + { + surround.clear(); + placements.clear(); + return; + } + + double x = logout.state.x; + double y = logout.state.y; + double z = logout.state.z; + double halfWidth = logout.state.width / 2.0; + + targetBlockPos = GPositionUtils.getRoundedBlockPos(x, y, z); + Box targetBox = new Box( + x - halfWidth, y, z - halfWidth, + x + halfWidth, y + logout.state.height, z + halfWidth + ); + + surround = getSurround(targetBlockPos, targetBox); + } + else { surround.clear(); placements.clear(); return; } - BlockPos targetBlockPos = GPositionUtils.getRoundedBlockPos(trapTarget.getX(), trapTarget.getY(), trapTarget.getZ()); - surround = getSurround(targetBlockPos, trapTarget); if (surround.isEmpty()) { return; @@ -314,6 +351,43 @@ private PlayerEntity getTrapTarget() .orElse(null); } + private GenyoLogoutSpots.Spot getNearestLogoutSpot() + { + if (!Modules.get().isActive(GenyoLogoutSpots.class)) + { + return null; + } + + GenyoLogoutSpots module = Modules.get().get(GenyoLogoutSpots.class); + List spots = module.getSpots(); + if (spots.isEmpty()) + { + return null; + } + + GenyoLogoutSpots.Spot best = null; + double bestDist = Double.MAX_VALUE; + + for (GenyoLogoutSpots.Spot spot : spots) + { + if (Managers.SOCIAL.isFriend(spot.name)) + { + continue; + } + + double dist = mc.player.squaredDistanceTo(spot.state.x, spot.state.y, spot.state.z); + if (dist > MathUtil.squared(placeRangeConfig.get()) || dist > bestDist) + { + continue; + } + + bestDist = dist; + best = spot; + } + + return best; + } + public void attackBlockingCrystals(List posList) { for (BlockPos pos : posList) @@ -359,9 +433,14 @@ public List getPlacementsFromSurround(List surround) } public List getSurround(BlockPos playerPos, PlayerEntity player) + { + return getSurround(playerPos, player.getBoundingBox()); + } + + public List getSurround(BlockPos playerPos, Box box) { List surroundBlocks = new ArrayList<>(); - List playerBlocks = getPlayerBlocks(playerPos, player); + List playerBlocks = getPlayerBlocks(playerPos, box); for (BlockPos pos : playerBlocks) { for (Direction dir : Direction.values()) @@ -428,11 +507,16 @@ public List getSurround(BlockPos playerPos, PlayerEntity player) } public List getPlayerBlocks(BlockPos playerPos, PlayerEntity entity) + { + return getPlayerBlocks(playerPos, entity.getBoundingBox()); + } + + public List getPlayerBlocks(BlockPos playerPos, Box box) { final List playerBlocks = new ArrayList<>(); if (extendConfig.get()) { - playerBlocks.addAll(GPositionUtils.getAllInBox(entity.getBoundingBox(), playerPos)); + playerBlocks.addAll(GPositionUtils.getAllInBox(box, playerPos)); } else { diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java new file mode 100644 index 0000000..8a406d6 --- /dev/null +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java @@ -0,0 +1,186 @@ +package com.genyo.systems.modules.visual; + + +import com.genyo.render.FrozenPlayerRenderState; +import com.genyo.render.PlayerWireframeRenderer; +import com.genyo.render.RenderStateCache; +import net.minecraft.client.render.entity.model.EntityModelLayer; +import net.minecraft.entity.player.PlayerSkinType; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.systems.modules.Categories; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.client.render.entity.model.EntityModelLayers; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.dimension.DimensionType; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class GenyoLogoutSpots extends Module { + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgRender = settings.createGroup("Render"); + + private final Setting lineColor = sgRender.add(new ColorSetting.Builder() + .name("line-color") + .description("Wireframe line color.") + .defaultValue(new SettingColor(255, 0, 255)) + .build() + ); + + private final Setting maxSpots = sgGeneral.add(new IntSetting.Builder() + .name("max-spots") + .description("Maximum number of logout spots to keep at once.") + .defaultValue(20) + .min(1) + .sliderMin(1) + .build() + ); + + private final List spots = new ArrayList<>(); + + private final List lastTabList = new ArrayList<>(); + private final List lastLoadedPlayers = new ArrayList<>(); + + private int timer; + private DimensionType lastDimension; + + public GenyoLogoutSpots() { + super(Categories.Render, "genyo-logout-spots", "Freezes an exact wireframe of a player at the moment they log out."); + } + + @Override + public void onActivate() { + spots.clear(); + lastTabList.clear(); + lastTabList.addAll(mc.getNetworkHandler().getPlayerList()); + refreshLoadedPlayers(); + + timer = 10; + lastDimension = mc.world.getDimension(); + } + + @Override + public void onDeactivate() { + spots.clear(); + lastTabList.clear(); + } + + private void refreshLoadedPlayers() { + lastLoadedPlayers.clear(); + for (Entity entity : mc.world.getEntities()) { + if (entity instanceof PlayerEntity player && player != mc.player) { + lastLoadedPlayers.add(player); + } + } + } + + @EventHandler + private void onTick(TickEvent.Post event) { + var currentTab = mc.getNetworkHandler().getPlayerList(); + + if (currentTab.size() != lastTabList.size()) { + for (PlayerListEntry oldEntry : lastTabList) { + UUID uuid = oldEntry.getProfile().id(); + + boolean stillInTab = currentTab.stream() + .anyMatch(e -> e.getProfile().id().equals(uuid)); + + if (!stillInTab) { + for (PlayerEntity real : lastLoadedPlayers) { + if (real.getUuid().equals(uuid)) { + addSpot(real); + break; + } + } + } + } + + lastTabList.clear(); + lastTabList.addAll(currentTab); + } + + if (timer <= 0) { + refreshLoadedPlayers(); + timer = 10; + } else { + timer--; + } + + DimensionType dimension = mc.world.getDimension(); + if (dimension != lastDimension) spots.clear(); + lastDimension = dimension; + } + + @EventHandler + private void onEntityAdded(meteordevelopment.meteorclient.events.entity.EntityAddedEvent event) { + // Player reconnected/came back into range — drop the stale spot for them + if (event.entity instanceof PlayerEntity real) { + spots.removeIf(spot -> spot.uuid.equals(real.getUuid())); + } + } + + private void addSpot(PlayerEntity real) { + FrozenPlayerRenderState frozen = RenderStateCache.freeze(real.getUuid()); + if (frozen == null) return; // no captured frame yet (e.g. player never rendered on screen), nothing to freeze + + spots.removeIf(s -> s.uuid.equals(real.getUuid())); + spots.add(new Spot(real.getUuid(), real.getName().getString(), frozen)); + + while (spots.size() > maxSpots.get()) { + spots.remove(0); + } + } + + @EventHandler + private void onRender3D(Render3DEvent event) { + for (Spot spot : spots) { + spot.render(event, lineColor.get()); + } + } + + @Override + public String getInfoString() { + return Integer.toString(spots.size()); + } + + public List getSpots() { + return spots; + } + + public static class Spot { + public final UUID uuid; + public final String name; + public final FrozenPlayerRenderState state; + + private final ModelPart modelPart; + private final BipedEntityModel model; + + @SuppressWarnings("unchecked") + public Spot(UUID uuid, String name, FrozenPlayerRenderState state) { + this.uuid = uuid; + this.name = name; + this.state = state; + + this.modelPart = net.minecraft.client.MinecraftClient.getInstance() + .getLoadedEntityModels() + .getModelPart(EntityModelLayers.PLAYER); + + this.model = new BipedEntityModel<>(modelPart); + this.model.setAngles(state); + } + + public void render(Render3DEvent event, meteordevelopment.meteorclient.utils.render.color.Color color) { + PlayerWireframeRenderer.render(event, modelPart, state.x, state.y, state.z, state.bodyYaw, color); + } + } +} diff --git a/src/main/resources/genyo.mixins.json b/src/main/resources/genyo.mixins.json index 31a398b..d825b24 100644 --- a/src/main/resources/genyo.mixins.json +++ b/src/main/resources/genyo.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_21", "client": [ "ClientPlayerInteractionManagerMixin", + "entity.player.MixinLivingEntityRenderer", "DefaultSettingsWidgetFactoryMixin", "FriendsInjector", "MixinConnectScreen", From 688d957d6d8bea1bfeed323768f31b738932538a Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 13:40:15 +0530 Subject: [PATCH 7/9] Added more settings to GenyoLogoutSpots --- .../genyo/render/PlayerWireframeRenderer.java | 87 +++++++++++++++++-- .../modules/visual/GenyoLogoutSpots.java | 41 ++++++++- 2 files changed, 117 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/genyo/render/PlayerWireframeRenderer.java b/src/main/java/com/genyo/render/PlayerWireframeRenderer.java index eaca883..d765368 100644 --- a/src/main/java/com/genyo/render/PlayerWireframeRenderer.java +++ b/src/main/java/com/genyo/render/PlayerWireframeRenderer.java @@ -1,7 +1,9 @@ package com.genyo.render; +import meteordevelopment.meteorclient.renderer.Renderer3D; import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.utils.render.color.Color; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.model.ModelPart; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.RotationAxis; @@ -16,18 +18,30 @@ public class PlayerWireframeRenderer { {0, 4}, {1, 5}, {2, 6}, {3, 7} // verticals connecting bottom to top }; + // 4 corner indices (winding order) per face of the box + private static final int[][] FACES = { + {0, 1, 2, 3}, // bottom + {4, 5, 6, 7}, // top + {0, 1, 5, 4}, + {1, 2, 6, 5}, + {2, 3, 7, 6}, + {3, 0, 4, 7} + }; + public static void render(Render3DEvent event, ModelPart root, double originX, double originY, double originZ, - float bodyYaw, Color color) { + float bodyYaw, Color lineColor, Color sideColor, double lineThickness) { + Renderer3D renderer = event.renderer; MatrixStack matrices = new MatrixStack(); - // Mirrors LivingEntityRenderer.render(): body-yaw rotation, then the - // model-space -> world-space flip and vertical offset used for every - // biped model render. matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F - bodyYaw)); matrices.scale(-1.0F, -1.0F, 1.0F); matrices.translate(0.0F, -1.501F, 0.0F); + // Camera position, used to billboard thick-line quads so they face the viewer + var cam = MinecraftClient.getInstance().gameRenderer.getCamera().getCameraPos(); + + root.forEachCuboid(matrices, (entry, path, index, cuboid) -> { Matrix4f mat = entry.getPositionMatrix(); @@ -42,20 +56,77 @@ public static void render(Render3DEvent event, ModelPart root, new Vector3f(cuboid.minX / 16f, cuboid.maxY / 16f, cuboid.maxZ / 16f), }; - for (Vector3f corner : corners) { - mat.transformPosition(corner); + for (Vector3f corner : corners) mat.transformPosition(corner); + + // Filled side faces + if (sideColor.a > 0) { + for (int[] face : FACES) { + Vector3f a = corners[face[0]]; + Vector3f b = corners[face[1]]; + Vector3f c = corners[face[2]]; + Vector3f d = corners[face[3]]; + + renderer.quad( + originX + a.x, originY + a.y, originZ + a.z, + originX + b.x, originY + b.y, originZ + b.z, + originX + c.x, originY + c.y, originZ + c.z, + originX + d.x, originY + d.y, originZ + d.z, + sideColor + ); + } } + // Wireframe edges, thickened into billboarded quads for (int[] edge : EDGES) { Vector3f a = corners[edge[0]]; Vector3f b = corners[edge[1]]; - event.renderer.line( + drawThickLine( + renderer, originX + a.x, originY + a.y, originZ + a.z, originX + b.x, originY + b.y, originZ + b.z, - color + lineColor, lineThickness, cam.x, cam.y, cam.z ); } }); } + + /** + * Draws a line as a camera-facing quad so it can be given a world-space thickness. + * Falls back visually to a hairline at very small thickness values. + */ + private static void drawThickLine(Renderer3D renderer, + double x1, double y1, double z1, + double x2, double y2, double z2, + Color color, double thickness, + double camX, double camY, double camZ) { + // Direction of the line segment + double dx = x2 - x1, dy = y2 - y1, dz = z2 - z1; + double len = Math.sqrt(dx * dx + dy * dy + dz * dz); + if (len < 1e-6) return; + dx /= len; dy /= len; dz /= len; + + // Vector from line midpoint to camera, used to find a perpendicular + double mx = (x1 + x2) / 2, my = (y1 + y2) / 2, mz = (z1 + z2) / 2; + double toCamX = camX - mx, toCamY = camY - my, toCamZ = camZ - mz; + + // perpendicular = normalize(dir x toCam) + double px = dy * toCamZ - dz * toCamY; + double py = dz * toCamX - dx * toCamZ; + double pz = dx * toCamY - dy * toCamX; + double plen = Math.sqrt(px * px + py * py + pz * pz); + if (plen < 1e-6) return; // line is pointing directly at camera, degenerate + double half = thickness / 32.0; // thickness setting is in "block/16ths"-ish units; tune to taste + px = px / plen * half; + py = py / plen * half; + pz = pz / plen * half; + + renderer.quad( + x1 - px, y1 - py, z1 - pz, + x1 + px, y1 + py, z1 + pz, + x2 + px, y2 + py, z2 + pz, + x2 - px, y2 - py, z2 - pz, + color + ); + } } diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java index 8a406d6..48b2c2b 100644 --- a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java @@ -11,6 +11,7 @@ import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.model.ModelPart; @@ -37,6 +38,34 @@ public class GenyoLogoutSpots extends Module { .build() ); + private final Setting sideColor = sgRender.add(new ColorSetting.Builder() + .name("side-color") + .description("Fill color for the wireframe's side faces.") + .defaultValue(new SettingColor(255, 0, 255)) + .build() + ); + + private final Setting sideOpacity = sgRender.add(new IntSetting.Builder() + .name("side-opacity") + .description("Opacity of the side face fill (0 = invisible, 255 = solid).") + .defaultValue(50) + .min(0) + .max(255) + .sliderMin(0) + .sliderMax(255) + .build() + ); + + private final Setting lineThickness = sgRender.add(new DoubleSetting.Builder() + .name("line-thickness") + .description("Thickness of the wireframe lines, in blocks.") + .defaultValue(0.02) + .min(0.005) + .sliderMin(0.005) + .sliderMax(0.15) + .build() + ); + private final Setting maxSpots = sgGeneral.add(new IntSetting.Builder() .name("max-spots") .description("Maximum number of logout spots to keep at once.") @@ -143,8 +172,13 @@ private void addSpot(PlayerEntity real) { @EventHandler private void onRender3D(Render3DEvent event) { + SettingColor side = sideColor.get(); + Color sideWithOpacity = new SettingColor(side.r, side.g, side.b, sideOpacity.get()); + Color line = lineColor.get(); + double thickness = lineThickness.get(); + for (Spot spot : spots) { - spot.render(event, lineColor.get()); + spot.render(event, line, sideWithOpacity, thickness); } } @@ -179,8 +213,9 @@ public Spot(UUID uuid, String name, FrozenPlayerRenderState state) { this.model.setAngles(state); } - public void render(Render3DEvent event, meteordevelopment.meteorclient.utils.render.color.Color color) { - PlayerWireframeRenderer.render(event, modelPart, state.x, state.y, state.z, state.bodyYaw, color); + public void render(Render3DEvent event, Color lineColor, Color sideColor, double lineThickness) { + PlayerWireframeRenderer.render(event, modelPart, state.x, state.y, state.z, state.bodyYaw, + lineColor, sideColor, lineThickness); } } } From fe7847c8edf5235c2adbe162efd55779c20a5ca5 Mon Sep 17 00:00:00 2001 From: Sleeepyv Date: Fri, 10 Jul 2026 14:37:01 +0530 Subject: [PATCH 8/9] Logout Spots with Names --- .../modules/visual/GenyoLogoutSpots.java | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java index 48b2c2b..9aec24c 100644 --- a/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java +++ b/src/main/java/com/genyo/systems/modules/visual/GenyoLogoutSpots.java @@ -6,6 +6,7 @@ import com.genyo.render.RenderStateCache; import net.minecraft.client.render.entity.model.EntityModelLayer; import net.minecraft.entity.player.PlayerSkinType; +import meteordevelopment.meteorclient.events.render.Render2DEvent; import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.systems.modules.Categories; @@ -14,6 +15,7 @@ import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.model.ModelPart; import net.minecraft.client.network.PlayerListEntry; import net.minecraft.client.render.entity.model.BipedEntityModel; @@ -21,6 +23,7 @@ import net.minecraft.client.render.entity.model.EntityModelLayers; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.dimension.DimensionType; import java.util.ArrayList; @@ -34,7 +37,7 @@ public class GenyoLogoutSpots extends Module { private final Setting lineColor = sgRender.add(new ColorSetting.Builder() .name("line-color") .description("Wireframe line color.") - .defaultValue(new SettingColor(255, 0, 255)) + .defaultValue(new SettingColor(85, 220, 255)) .build() ); @@ -48,7 +51,7 @@ public class GenyoLogoutSpots extends Module { private final Setting sideOpacity = sgRender.add(new IntSetting.Builder() .name("side-opacity") .description("Opacity of the side face fill (0 = invisible, 255 = solid).") - .defaultValue(50) + .defaultValue(30) .min(0) .max(255) .sliderMin(0) @@ -59,13 +62,28 @@ public class GenyoLogoutSpots extends Module { private final Setting lineThickness = sgRender.add(new DoubleSetting.Builder() .name("line-thickness") .description("Thickness of the wireframe lines, in blocks.") - .defaultValue(0.02) + .defaultValue(0.150) .min(0.005) .sliderMin(0.005) .sliderMax(0.15) .build() ); + private final Setting showNames = sgRender.add(new BoolSetting.Builder() + .name("show-names") + .description("Renders the player's name above their logout spot.") + .defaultValue(true) + .build() + ); + + private final Setting nameColor = sgRender.add(new ColorSetting.Builder() + .name("name-color") + .description("Color of the player name text.") + .defaultValue(new SettingColor(255, 255, 255)) + .visible(showNames::get) + .build() + ); + private final Setting maxSpots = sgGeneral.add(new IntSetting.Builder() .name("max-spots") .description("Maximum number of logout spots to keep at once.") @@ -182,6 +200,29 @@ private void onRender3D(Render3DEvent event) { } } + @EventHandler + private void onRender2D(Render2DEvent event) { + if (!showNames.get() || spots.isEmpty()) return; + + Color color = nameColor.get(); + + for (Spot spot : spots) { + // Head height roughly matches the frozen state's standing eye height + Vec3d worldPos = new Vec3d(spot.state.x, spot.state.y + spot.state.standingEyeHeight + 0.3, spot.state.z); + + Vec3d screen = mc.gameRenderer.project(worldPos); + // project() returns NDC-like coords; z outside [0,1] roughly means behind/outside camera + if (screen.z < 0 || screen.z > 1) continue; + + int x = (int) ((screen.x * 0.5 + 0.5) * mc.getWindow().getScaledWidth()); + int y = (int) ((1.0 - (screen.y * 0.5 + 0.5)) * mc.getWindow().getScaledHeight()); + + DrawContext ctx = event.drawContext; + int textWidth = mc.textRenderer.getWidth(spot.name); + ctx.drawText(mc.textRenderer, spot.name, x - textWidth / 2, y, color.getPacked(), true); + } + } + @Override public String getInfoString() { return Integer.toString(spots.size()); From a63956c303575f46763f35935663885430282c31 Mon Sep 17 00:00:00 2001 From: wuritz Date: Fri, 10 Jul 2026 17:53:47 +0200 Subject: [PATCH 9/9] Missed a thing in MineESP --- src/main/java/com/genyo/systems/modules/combat/MineESP.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/genyo/systems/modules/combat/MineESP.java b/src/main/java/com/genyo/systems/modules/combat/MineESP.java index a70345c..b0ce89d 100644 --- a/src/main/java/com/genyo/systems/modules/combat/MineESP.java +++ b/src/main/java/com/genyo/systems/modules/combat/MineESP.java @@ -31,6 +31,7 @@ public enum RenderMode { } private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgColors = settings.createGroup("Colors"); private final SettingGroup sgRender = settings.createGroup("Render"); private final Setting radius = sgGeneral.add(new DoubleSetting.Builder()