diff --git a/c b/c deleted file mode 100644 index 7827b4f..0000000 --- a/c +++ /dev/null @@ -1,258 +0,0 @@ -commit 126b7ef4a72da1b9b80c0b8b585e91afec6f264d (HEAD -> brasil, origin/brasil) -Author: wuritz -Date: Sun Jul 20 11:25:06 2025 +0200 - - elvileg minden fasza - -commit 45f8d95e94d6a315877558b904a7d3643c4b4a50 -Author: wuritz -Date: Sat Jul 19 23:28:17 2025 +0200 - - genyo blink - -commit 8585ef7b6b26a394e9b5b303ffa3d317ee30e026 -Author: wuritz -Date: Sat Jul 19 20:10:08 2025 +0200 - - genyo welcome - -commit 873fef998b57508b046822ee8200c3ed2004db45 -Author: wuritz -Date: Tue Jul 15 13:17:29 2025 +0200 - - genyo module - -commit 684f30a22faf7ba289dbef206c0bce865ef1178f -Author: wuritz -Date: Mon Jul 14 23:39:58 2025 +0200 - - mostmar nem crashel 1 sizeos listaknal - -commit e4d8682cbe5e2a3bc108890f42d1089fdd2e6725 -Author: wuritz -Date: Mon Jul 14 23:24:22 2025 +0200 - - surround wooo - -commit 0b7cb632ac7c5fdc6e5f86fa99ff4fc945b4d39b -Author: wuritz -Date: Sat Jul 12 13:52:15 2025 +0200 - - in combat, csak nem mukszik a cooldown render - -commit 6fc6afd9a845901f72964ebe7d5dbee343ae05b1 -Author: wuritz -Date: Fri Jul 11 09:09:51 2025 +0200 - - mukszik a trajectory - -commit 4049f1e163b1ead7fde4b0cf5e56326339d64e20 -Author: wuritz -Date: Thu Jul 10 08:54:30 2025 +0200 - - yeee - -commit 0b86ffab0df3225bd308f400d362b9b68df0ece2 -Author: wuritz -Date: Thu Jul 10 08:43:51 2025 +0200 - - mukszik a traj - -commit 1d372e2576bffe9b3f312b62a8eb0388dbbe69e5 -Author: wuritz -Date: Tue Jul 8 10:01:27 2025 +0200 - - hulkenberg megin jobb - -commit 4a872fe9270ad40c89cd046e177036a1799aa489 -Merge: 317d537 2562cca -Author: wuritz -Date: Mon Jul 7 23:25:40 2025 +0200 - - Merge remote-tracking branch 'origin/brasil' into brasil - -commit 317d537222c3ad745e5712daddb0a85fbed3065f -Author: wuritz -Date: Mon Jul 7 23:24:19 2025 +0200 - - igen - -commit 2562ccaa0fc3630216d0144b4b13a9619176adbe -Author: wuritz -Date: Mon Jul 7 23:24:19 2025 +0200 - - igen - -commit 86890891ccacb94852b744c9ad6edcf388232e31 -Author: wuritz -Date: Mon Jul 7 23:08:09 2025 +0200 - - eltunik yooooo - -commit 7bb49127b383d418f6cbe7a77ff3ffb2b5800312 -Author: wuritz -Date: Sun Jul 6 22:08:25 2025 +0200 - - rossz wolt az accesswidener - -commit 995c1ffb840e8a0479accf95768206f63abdce69 -Author: wuritz -Date: Sun Jul 6 22:04:26 2025 +0200 - - angel hulkenberg - -commit 23c39a8ed8f0a6c5208d67391c34fa54d7feea17 -Author: wuritz -Date: Sun Jul 6 22:01:26 2025 +0200 - - angel hulkenberg - -commit df318ca9711c31389c38699bbcf473d69feea97d -Author: wuritz -Date: Sun Jun 29 11:59:01 2025 +0200 - - meg mielott elbasznam - -commit 4ea49baeb95b592d23945b11cb41050b61975587 -Author: wuritz -Date: Sun Jun 22 23:29:50 2025 +0200 - - enemies - -commit 6a30b7b503cf8d9d0f119cb4201ba21cf1da5c84 -Author: wuritz -Date: Sun Jun 22 13:25:02 2025 +0200 - - auto ez? - -commit 0dc1bf617d431bace2c47f2575f4ebd7dda7307e -Author: wuritz -Date: Sun Jun 22 12:18:42 2025 +0200 - - auto ez - -commit 85360639a1a1dcf341b09f1641fea9241f24089d -Author: wuritz -Date: Sun Jun 22 11:17:31 2025 +0200 - - fasz genyo fasz - -commit d48c94bb0ee3b401bc5b5e010871b9e271ee0304 -Author: wuritz -Date: Sun Jun 22 00:41:24 2025 +0200 - - ffffa - -commit 7f1a37ef88f596fa3fd6a40cc4807f0c896d4bd7 -Author: wuritz -Date: Sat Jun 21 12:42:02 2025 +0200 - - fass - -commit f1dc1d886e8fd37dc5f3c1a734a4cd5527572150 -Author: wuritz -Date: Sat Jun 21 12:40:38 2025 +0200 - - mixin - -commit b4451d7b8b2fc6854e7bc6e0e5fc90e94a228a1d -Author: wuritz -Date: Sat Jun 21 12:25:55 2025 +0200 - - genyo jobb - -commit 05aff3e3d7f3b0483466ee5fdad4a2de7c394668 -Author: wuritz -Date: Sat Jun 21 12:23:36 2025 +0200 - - genyo genyo mostmar jobb - -commit fe5dde06cfb19008ecb50d6b5b22fa7cd4b1da46 (tag: Genyo) -Author: wuritz -Date: Sat Jun 21 00:32:47 2025 +0200 - - genyo - -commit 35369cd1008714863ea7590ab07bc264d58aed24 -Author: wuritz -Date: Sat Jun 21 00:15:46 2025 +0200 - - genyo - -commit ab2baad46f6f690e349d16d0582ace26e64b6d66 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:22:12 2025 +0200 - - Delete gradle directory - -commit de406708b999be0647fa935127478a0272918013 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:22:07 2025 +0200 - - Delete src directory - -commit 98edadca233013c294cd39d0713f403e8255c588 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:22:01 2025 +0200 - - Delete .editorconfig - -commit a8c35152f0e7f6332e124f763cf9a8c142c2bcc2 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:53 2025 +0200 - - Delete .gitignore - -commit 58dc8f4c2321916ef72ac45ab81a893f2d950649 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:48 2025 +0200 - - Delete LICENSE - -commit 785b4b5df405b753d2a148c1a30fa3bae3e2c631 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:43 2025 +0200 - - Delete gradle.properties - -commit c817557346c4c12497d65091d86481ce9de28f51 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:37 2025 +0200 - - Delete README.md - -commit f0a7e33dfa3a03163d322bae3d17ce772e78bff7 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:28 2025 +0200 - - Delete gradlew - -commit 7e7f590e3cf157f693911e0a48e2399d496d3d0d -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:23 2025 +0200 - - Delete gradlew.bat - -commit 18e4ecb04105053425646330d501653bb9bc6d8e -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:18 2025 +0200 - - Delete settings.gradle.kts - -commit 01afc005e32fac81c1935fe6c974a7b09c890f32 -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:21:09 2025 +0200 - - Delete build.gradle.kts - -commit 77e40d543a743324c8a4e0d0cf56c98dd141a5cf -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Sat Jun 21 00:20:46 2025 +0200 - - Delete .github/workflows directory - -commit edb5a105974719a364cd2f9fc651ffff88b2792e -Author: Ritz Richárd <38112734+wuritz@users.noreply.github.com> -Date: Fri Jun 20 21:05:32 2025 +0200 - - Initial commit diff --git a/gradle.properties b/gradle.properties index 8fbe06d..1bb129f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,8 +6,11 @@ yarn_mappings=1.21.4+build.8 loader_version=0.16.14 # Mod Properties -mod_version=0.7.3 +mod_version=0.8.0 maven_group=com.genyo archives_base_name=genyo-addon # Dependencies + +# DiscordRPC (https://github.com/MeteorDevelopment/java-discord-rpc) +discordipc_version=1.1 diff --git a/src/main/java/com/genyo/addon/GenyoAddon.java b/src/main/java/com/genyo/addon/GenyoAddon.java index ffc8433..eb17827 100644 --- a/src/main/java/com/genyo/addon/GenyoAddon.java +++ b/src/main/java/com/genyo/addon/GenyoAddon.java @@ -1,6 +1,12 @@ package com.genyo.addon; -import com.genyo.addon.modules.*; +import com.genyo.addon.hud.ActiveGenyoHud; +import com.genyo.addon.modules.combat.*; +import com.genyo.addon.modules.misc.*; +import com.genyo.addon.modules.movement.GenyoVelocity; +import com.genyo.addon.modules.visual.AngelSexHulkenberg; +import com.genyo.addon.modules.visual.GenyoPenisESP; +import com.genyo.addon.modules.world.*; import com.genyo.addon.systems.enemies.EnemiesTab; import com.genyo.addon.hud.InCombatHud; import com.genyo.addon.hud.PvPNeccessaryHud; @@ -17,6 +23,10 @@ import meteordevelopment.meteorclient.systems.hud.HudGroup; import meteordevelopment.meteorclient.systems.modules.Category; import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.misc.DiscordPresence; +import meteordevelopment.meteorclient.utils.misc.Version; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.item.Items; import org.slf4j.Logger; @@ -26,10 +36,34 @@ public class GenyoAddon extends MeteorAddon { public static final Category GENYO = new Category("Genyo", Items.MILK_BUCKET.getDefaultStack()); public static final HudGroup HUD_GROUP = new HudGroup("Genyo"); + public static final String MOD_ID = "genyo"; + public static final ModMetadata MOD_META; + public static final String NAME; + public static final Version VERSION; + + static { + MOD_META = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().getMetadata(); + + NAME = MOD_META.getName(); + + String versionString = MOD_META.getVersion().getFriendlyString(); + if (versionString.contains("-")) versionString = versionString.split("-")[0]; + + // When building and running through IntelliJ and not Gradle it doesn't replace the version so just use a dummy + if (versionString.equals("${version}")) versionString = "0.0.0"; + + VERSION = new Version(versionString); + } + @Override public void onInitialize() { LOG.info("Genyo fasz indul genyo"); + if (Modules.get().isActive(DiscordPresence.class)) { + Modules.get().get(DiscordPresence.class).toggle(); + LOG.info("oh no la policia"); + } + // Tabs initTabs(); @@ -62,11 +96,28 @@ private void initModules(Modules modules) { modules.add(new GenyoWelcome()); modules.add(new GenyoSkinBlink()); modules.add(new GenyoGoodbye()); + modules.add(new GenyoAutoMine()); + modules.add(new GenyoSurroundV2()); + modules.add(new GenyoAutoCrystal()); + modules.add(new GenyoDiscord()); + modules.add(new GenyoSpeedmine()); + modules.add(new GenyoAutoTool()); + modules.add(new GenyoReplenish()); + modules.add(new GenyoScaffold()); + modules.add(new GenyoPenisESP()); + modules.add(new GenyoAutoTotem()); + modules.add(new GenyoVelocity()); + modules.add(new KFCSpawnKill()); + modules.add(new GenyoCriticals()); + modules.add(new GenyoGhostBlocks()); + modules.add(new GenyoSelfTrap()); + modules.add(new CombatBrainrot()); } private void initHUD(Hud hud) { hud.register(PvPNeccessaryHud.INFO); hud.register(InCombatHud.INFO); + hud.register(ActiveGenyoHud.INFO); } @Override diff --git a/src/main/java/com/genyo/addon/events/AttackBlockEvent.java b/src/main/java/com/genyo/addon/events/AttackBlockEvent.java new file mode 100644 index 0000000..27c5e5a --- /dev/null +++ b/src/main/java/com/genyo/addon/events/AttackBlockEvent.java @@ -0,0 +1,27 @@ +package com.genyo.addon.events; + +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +public class AttackBlockEvent extends Cancellable { + private static final AttackBlockEvent INSTANCE = new AttackBlockEvent(); + + public BlockPos pos; + public BlockState state; + public Direction direction; + + /** + * @param pos + * @param state + * @param direction + */ + public static AttackBlockEvent get(BlockPos pos, BlockState state, Direction direction) { + INSTANCE.pos = pos; + INSTANCE.state = state; + INSTANCE.direction = direction; + + return INSTANCE; + } +} diff --git a/src/main/java/com/genyo/addon/events/RunTickEvent.java b/src/main/java/com/genyo/addon/events/RunTickEvent.java new file mode 100644 index 0000000..ad8cae5 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/RunTickEvent.java @@ -0,0 +1,4 @@ +package com.genyo.addon.events; + +public class RunTickEvent { +} diff --git a/src/main/java/com/genyo/addon/events/StageEvent.java b/src/main/java/com/genyo/addon/events/StageEvent.java new file mode 100644 index 0000000..9b2ed93 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/StageEvent.java @@ -0,0 +1,19 @@ +package com.genyo.addon.events; + +public class StageEvent { + + private EventStage stage; + + public void setStage(EventStage stage) { + this.stage = stage; + } + + public EventStage getStage() { + return stage; + } + + public enum EventStage { + PRE, + POST + } +} diff --git a/src/main/java/com/genyo/addon/events/entity/EntityDeathEvent.java b/src/main/java/com/genyo/addon/events/entity/EntityDeathEvent.java new file mode 100644 index 0000000..b10cb02 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/entity/EntityDeathEvent.java @@ -0,0 +1,17 @@ +package com.genyo.addon.events.entity; + +import net.minecraft.entity.LivingEntity; + +public class EntityDeathEvent { + + private static final EntityDeathEvent INSTANCE = new EntityDeathEvent(); + + public LivingEntity entity; + + public EntityDeathEvent get(LivingEntity entity) { + INSTANCE.entity = entity; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/entity/RenderPlayerEvent.java b/src/main/java/com/genyo/addon/events/entity/RenderPlayerEvent.java new file mode 100644 index 0000000..b67a464 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/entity/RenderPlayerEvent.java @@ -0,0 +1,26 @@ +package com.genyo.addon.events.entity; + +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.client.network.AbstractClientPlayerEntity; + +public class RenderPlayerEvent extends Cancellable { + + private static final RenderPlayerEvent INSTANCE = new RenderPlayerEvent(); + + // + public AbstractClientPlayerEntity entity; + // + public float yaw; + public float pitch; + + /** + * @param entity + */ + public static RenderPlayerEvent get(AbstractClientPlayerEntity entity) + { + INSTANCE.entity = entity; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/entity/player/PushEntityEvent.java b/src/main/java/com/genyo/addon/events/entity/player/PushEntityEvent.java new file mode 100644 index 0000000..835f28f --- /dev/null +++ b/src/main/java/com/genyo/addon/events/entity/player/PushEntityEvent.java @@ -0,0 +1,19 @@ +package com.genyo.addon.events.entity.player; + +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.entity.Entity; + +public class PushEntityEvent extends Cancellable { + + private static final PushEntityEvent INSTANCE = new PushEntityEvent(); + + public Entity pushed, pusher; + + public static PushEntityEvent get(Entity pushed, Entity pusher) { + INSTANCE.pushed = pushed; + INSTANCE.pusher = pusher; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/entity/player/PushFluidsEvent.java b/src/main/java/com/genyo/addon/events/entity/player/PushFluidsEvent.java new file mode 100644 index 0000000..8ef6234 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/entity/player/PushFluidsEvent.java @@ -0,0 +1,7 @@ +package com.genyo.addon.events.entity.player; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class PushFluidsEvent extends Cancellable { + +} diff --git a/src/main/java/com/genyo/addon/events/keyboard/KeyboardTickEvent.java b/src/main/java/com/genyo/addon/events/keyboard/KeyboardTickEvent.java new file mode 100644 index 0000000..e4f0e74 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/keyboard/KeyboardTickEvent.java @@ -0,0 +1,34 @@ +package com.genyo.addon.events.keyboard; + +import meteordevelopment.meteorclient.events.Cancellable; +import meteordevelopment.meteorclient.events.world.TickEvent; +import net.minecraft.client.input.Input; + +public class KeyboardTickEvent extends Cancellable { + + public static class Pre extends KeyboardTickEvent { + private static final Pre INSTANCE = new Pre(); + + public Input input; + + public static Pre get(Input input) { + INSTANCE.input = input; + + return INSTANCE; + } + } + + public static class Post extends KeyboardTickEvent { + private static final Post INSTANCE = new Post(); + + public Input input; + + public static Post get(Input input) { + INSTANCE.input = input; + + return INSTANCE; + } + } + + +} diff --git a/src/main/java/com/genyo/addon/events/meteor/SettingChangedEvent.java b/src/main/java/com/genyo/addon/events/meteor/SettingChangedEvent.java new file mode 100644 index 0000000..4e4db2b --- /dev/null +++ b/src/main/java/com/genyo/addon/events/meteor/SettingChangedEvent.java @@ -0,0 +1,17 @@ +package com.genyo.addon.events.meteor; + +import meteordevelopment.meteorclient.settings.Setting; + +public class SettingChangedEvent { + + private static final SettingChangedEvent INSTANCE = new SettingChangedEvent(); + + public Setting setting; + + public static SettingChangedEvent get(Setting setting) { + INSTANCE.setting = setting; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/network/ConnectScreenEvent.java b/src/main/java/com/genyo/addon/events/network/ConnectScreenEvent.java new file mode 100644 index 0000000..892c0e4 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/ConnectScreenEvent.java @@ -0,0 +1,19 @@ +package com.genyo.addon.events.network; + +import net.minecraft.client.network.ServerAddress; +import net.minecraft.client.network.ServerInfo; + +public class ConnectScreenEvent { + + private static final ConnectScreenEvent INSTANCE = new ConnectScreenEvent(); + + public ServerAddress address; + public ServerInfo info; + + public static ConnectScreenEvent get(ServerAddress address, ServerInfo info) { + INSTANCE.address = address; + INSTANCE.info = info; + + return INSTANCE; + } +} diff --git a/src/main/java/com/genyo/addon/events/network/DisconnectEvent.java b/src/main/java/com/genyo/addon/events/network/DisconnectEvent.java new file mode 100644 index 0000000..aa9c99c --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/DisconnectEvent.java @@ -0,0 +1,4 @@ +package com.genyo.addon.events.network; + +public class DisconnectEvent { +} diff --git a/src/main/java/com/genyo/addon/events/network/ItemDesyncEvent.java b/src/main/java/com/genyo/addon/events/network/ItemDesyncEvent.java new file mode 100644 index 0000000..a2354f3 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/ItemDesyncEvent.java @@ -0,0 +1,23 @@ +package com.genyo.addon.events.network; + +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.item.ItemStack; + +public class ItemDesyncEvent extends Cancellable { + + private static final ItemDesyncEvent INSTANCE = new ItemDesyncEvent(); + + public ItemStack stack; + + public static ItemDesyncEvent get(ItemStack stack) { + INSTANCE.stack = stack; + + return INSTANCE; + } + + public void setStack(ItemStack stack) + { + this.stack = stack; + } + +} diff --git a/src/main/java/com/genyo/addon/events/network/MovementPacketsEvent.java b/src/main/java/com/genyo/addon/events/network/MovementPacketsEvent.java new file mode 100644 index 0000000..96ff31e --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/MovementPacketsEvent.java @@ -0,0 +1,26 @@ +package com.genyo.addon.events.network; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class MovementPacketsEvent extends Cancellable { + + private static final MovementPacketsEvent INSTANCE = new MovementPacketsEvent(); + + // + public double x, y, z; + public float yaw, pitch; + public boolean onGround; + + public static MovementPacketsEvent get(double x, double y, double z, float yaw, float pitch, boolean onGround) + { + INSTANCE.x = x; + INSTANCE.y = y; + INSTANCE.z = z; + INSTANCE.yaw = yaw; + INSTANCE.pitch = pitch; + INSTANCE.onGround = onGround; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/network/PacketSneakingEvent.java b/src/main/java/com/genyo/addon/events/network/PacketSneakingEvent.java new file mode 100644 index 0000000..5ab558a --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/PacketSneakingEvent.java @@ -0,0 +1,7 @@ +package com.genyo.addon.events.network; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class PacketSneakingEvent extends Cancellable { + +} diff --git a/src/main/java/com/genyo/addon/events/network/PlayerTickEvent.java b/src/main/java/com/genyo/addon/events/network/PlayerTickEvent.java new file mode 100644 index 0000000..149fa29 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/PlayerTickEvent.java @@ -0,0 +1,4 @@ +package com.genyo.addon.events.network; + +public class PlayerTickEvent { +} diff --git a/src/main/java/com/genyo/addon/events/network/PlayerUpdateEvent.java b/src/main/java/com/genyo/addon/events/network/PlayerUpdateEvent.java new file mode 100644 index 0000000..5093f78 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/PlayerUpdateEvent.java @@ -0,0 +1,19 @@ +package com.genyo.addon.events.network; + +import com.genyo.addon.events.StageEvent; + +public class PlayerUpdateEvent extends StageEvent { + + private static final PlayerUpdateEvent INSTANCE = new PlayerUpdateEvent(); + + public float yaw; + public float pitch; + + public static PlayerUpdateEvent get(float yaw, float pitch) { + INSTANCE.yaw = yaw; + INSTANCE.pitch = pitch; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/network/PushOutOfBlocksEvent.java b/src/main/java/com/genyo/addon/events/network/PushOutOfBlocksEvent.java new file mode 100644 index 0000000..ec1e8d2 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/PushOutOfBlocksEvent.java @@ -0,0 +1,6 @@ +package com.genyo.addon.events.network; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class PushOutOfBlocksEvent extends Cancellable { +} diff --git a/src/main/java/com/genyo/addon/events/network/SetCurrentHandEvent.java b/src/main/java/com/genyo/addon/events/network/SetCurrentHandEvent.java new file mode 100644 index 0000000..0a457c4 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/network/SetCurrentHandEvent.java @@ -0,0 +1,26 @@ +package com.genyo.addon.events.network; + +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class SetCurrentHandEvent extends Cancellable { + + private static final SetCurrentHandEvent INSTANCE = new SetCurrentHandEvent(); + + public Hand hand; + + public static SetCurrentHandEvent get(Hand hand) { + INSTANCE.hand = hand; + + return INSTANCE; + } + + public ItemStack getStackInHand() + { + return mc.player.getStackInHand(hand); + } + +} diff --git a/src/main/java/com/genyo/addon/events/render/RenderWorldEvent.java b/src/main/java/com/genyo/addon/events/render/RenderWorldEvent.java new file mode 100644 index 0000000..f82c3fa --- /dev/null +++ b/src/main/java/com/genyo/addon/events/render/RenderWorldEvent.java @@ -0,0 +1,48 @@ +package com.genyo.addon.events.render; + +import net.minecraft.client.util.math.MatrixStack; + +public class RenderWorldEvent { + + private static final RenderWorldEvent INSTANCE = new RenderWorldEvent(); + + // + public MatrixStack matrices; + public float tickDelta; + + /** + * @param matrices + */ + public static RenderWorldEvent get(MatrixStack matrices, float tickDelta) { + INSTANCE.matrices = matrices; + INSTANCE.tickDelta = tickDelta; + + return INSTANCE; + } + + public static class Game extends RenderWorldEvent + { + + /** + * @param matrices + * @param tickDelta + */ + public Game(MatrixStack matrices, float tickDelta) + { + RenderWorldEvent.get(matrices, tickDelta); + } + } + + public static class Hand extends RenderWorldEvent + { + /** + * @param matrices + * @param tickDelta + */ + public Hand(MatrixStack matrices, float tickDelta) + { + RenderWorldEvent.get(matrices, tickDelta); + } + } + +} diff --git a/src/main/java/com/genyo/addon/events/render/TickCounterEvent.java b/src/main/java/com/genyo/addon/events/render/TickCounterEvent.java new file mode 100644 index 0000000..ba7b563 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/render/TickCounterEvent.java @@ -0,0 +1,16 @@ +package com.genyo.addon.events.render; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class TickCounterEvent extends Cancellable { + + private static final TickCounterEvent INSTANCE = new TickCounterEvent(); + public float ticks; + + public static TickCounterEvent get(float ticks) { + INSTANCE.ticks = ticks; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/events/sync/SyncEvent.java b/src/main/java/com/genyo/addon/events/sync/SyncEvent.java new file mode 100644 index 0000000..24b13da --- /dev/null +++ b/src/main/java/com/genyo/addon/events/sync/SyncEvent.java @@ -0,0 +1,30 @@ +package com.genyo.addon.events.sync; + +import meteordevelopment.meteorclient.events.Cancellable; + +public class SyncEvent extends Cancellable { + + public static class Pre extends SyncEvent { + private static final Pre INSTANCE = new Pre(); + + public float yaw; + public float pitch; + public Runnable postAction; + + public static Pre get(float yaw, float pitch) { + INSTANCE.yaw = yaw; + INSTANCE.pitch = pitch; + + return INSTANCE; + } + } + + public static class Post extends SyncEvent { + private static final Post INSTANCE = new Post(); + + public static Post get() { + return INSTANCE; + } + } + +} diff --git a/src/main/java/com/genyo/addon/events/world/CollisionEvent.java b/src/main/java/com/genyo/addon/events/world/CollisionEvent.java new file mode 100644 index 0000000..87b7ad1 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/world/CollisionEvent.java @@ -0,0 +1,32 @@ +package com.genyo.addon.events.world; + +import com.mojang.blaze3d.systems.RenderSystem; +import meteordevelopment.meteorclient.events.Cancellable; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; + +public class CollisionEvent extends Cancellable { + + private static final CollisionEvent INSTANCE = new CollisionEvent(); + + public BlockState state; + public BlockPos pos; + public VoxelShape shape; + + public static CollisionEvent get(BlockState bs, BlockPos bp, VoxelShape vs) { + CollisionEvent event = INSTANCE; + + if (!RenderSystem.isOnRenderThread()) { + event = new CollisionEvent(); + } + + event.setCancelled(false); + event.state = bs; + event.pos = bp; + event.shape = vs; + + return event; + } + +} diff --git a/src/main/java/com/genyo/addon/events/world/LoadWorldEvent.java b/src/main/java/com/genyo/addon/events/world/LoadWorldEvent.java new file mode 100644 index 0000000..e0859c6 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/world/LoadWorldEvent.java @@ -0,0 +1,4 @@ +package com.genyo.addon.events.world; + +public class LoadWorldEvent { +} diff --git a/src/main/java/com/genyo/addon/events/world/RemoveEntityEvent.java b/src/main/java/com/genyo/addon/events/world/RemoveEntityEvent.java new file mode 100644 index 0000000..810487b --- /dev/null +++ b/src/main/java/com/genyo/addon/events/world/RemoveEntityEvent.java @@ -0,0 +1,19 @@ +package com.genyo.addon.events.world; + +import net.minecraft.entity.Entity; + +public class RemoveEntityEvent { + + private static final RemoveEntityEvent INSTANCE = new RemoveEntityEvent(); + + public Entity entity; + public Entity.RemovalReason removalReason; + + public static RemoveEntityEvent get(Entity entity, Entity.RemovalReason removalReason) { + INSTANCE.entity = entity; + INSTANCE.removalReason = removalReason; + + return INSTANCE; + } + +} diff --git a/src/main/java/com/genyo/addon/hud/ActiveGenyoHud.java b/src/main/java/com/genyo/addon/hud/ActiveGenyoHud.java new file mode 100644 index 0000000..f855bae --- /dev/null +++ b/src/main/java/com/genyo/addon/hud/ActiveGenyoHud.java @@ -0,0 +1,372 @@ +package com.genyo.addon.hud; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.modules.GenyoModule; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.hud.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; + +import java.util.ArrayList; +import java.util.List; + +public class ActiveGenyoHud extends HudElement { + + public static final HudElementInfo INFO = new HudElementInfo<>(GenyoAddon.HUD_GROUP, "active-genyo", "Displays your active GENYO modules.", ActiveGenyoHud::new); + + private static final Color WHITE = new Color(); + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgColor = settings.createGroup("Color"); + private final SettingGroup sgScale = settings.createGroup("Scale"); + private final SettingGroup sgBackground = settings.createGroup("Background"); + + private final Setting sort = sgGeneral.add(new EnumSetting.Builder() + .name("sort") + .description("How to sort active modules.") + .defaultValue(Sort.Biggest) + .build() + ); + + private final Setting activeInfo = sgGeneral.add(new BoolSetting.Builder() + .name("module-info") + .description("Shows info from the module next to the name in the active modules list.") + .defaultValue(true) + .build() + ); + + private final Setting showKeybind = sgGeneral.add(new BoolSetting.Builder() + .name("show-keybind") + .description("Shows the module's keybind next to its name.") + .defaultValue(false) + .build() + ); + + private final Setting shadow = sgGeneral.add(new BoolSetting.Builder() + .name("shadow") + .description("Renders shadow behind text.") + .defaultValue(true) + .build() + ); + + private final Setting outlines = sgGeneral.add(new BoolSetting.Builder() + .name("outlines") + .description("Whether or not to render outlines") + .defaultValue(false) + .build() + ); + + private final Setting outlineWidth = sgGeneral.add(new IntSetting.Builder() + .name("outline-width") + .description("Outline width") + .defaultValue(2) + .min(1) + .sliderMin(1) + .visible(outlines::get) + .build() + ); + + private final Setting alignment = sgGeneral.add(new EnumSetting.Builder() + .name("alignment") + .description("Horizontal alignment.") + .defaultValue(Alignment.Auto) + .build() + ); + + // Color + + private final Setting colorMode = sgColor.add(new EnumSetting.Builder() + .name("color-mode") + .description("What color to use for active modules.") + .defaultValue(ColorMode.Rainbow) + .build() + ); + + private final Setting flatColor = sgColor.add(new ColorSetting.Builder() + .name("flat-color") + .description("Color for flat color mode.") + .defaultValue(new SettingColor(225, 25, 25)) + .visible(() -> colorMode.get() == ColorMode.Flat) + .build() + ); + + private final Setting rainbowSpeed = sgColor.add(new DoubleSetting.Builder() + .name("rainbow-speed") + .description("Rainbow speed of rainbow color mode.") + .defaultValue(0.05) + .sliderMin(0.01) + .sliderMax(0.2) + .decimalPlaces(4) + .visible(() -> colorMode.get() == ColorMode.Rainbow) + .build() + ); + + private final Setting rainbowSpread = sgColor.add(new DoubleSetting.Builder() + .name("rainbow-spread") + .description("Rainbow spread of rainbow color mode.") + .defaultValue(0.01) + .sliderMin(0.001) + .sliderMax(0.05) + .decimalPlaces(4) + .visible(() -> colorMode.get() == ColorMode.Rainbow) + .build() + ); + + private final Setting rainbowSaturation = sgColor.add(new DoubleSetting.Builder() + .name("rainbow-saturation") + .defaultValue(1.0d) + .sliderRange(0.0d, 1.0d) + .visible(() -> colorMode.get() == ColorMode.Rainbow) + .build() + ); + + private final Setting rainbowBrightness = sgColor.add(new DoubleSetting.Builder() + .name("rainbow-brightness") + .defaultValue(1.0d) + .sliderRange(0.0d, 1.0d) + .visible(() -> colorMode.get() == ColorMode.Rainbow) + .build() + ); + + private final Setting moduleInfoColor = sgColor.add(new ColorSetting.Builder() + .name("module-info-color") + .description("Color of module info text.") + .defaultValue(new SettingColor(175, 175, 175)) + .visible(activeInfo::get) + .build() + ); + + // Scale + + private final Setting customScale = sgScale.add(new BoolSetting.Builder() + .name("custom-scale") + .description("Applies a custom scale to this hud element.") + .defaultValue(false) + .build() + ); + + private final Setting scale = sgScale.add(new DoubleSetting.Builder() + .name("scale") + .description("Custom scale.") + .visible(customScale::get) + .defaultValue(1) + .min(0.5) + .sliderRange(0.5, 3) + .build() + ); + + // Background + + private final Setting background = sgBackground.add(new BoolSetting.Builder() + .name("background") + .description("Displays background.") + .defaultValue(false) + .build() + ); + + private final Setting backgroundColor = sgBackground.add(new ColorSetting.Builder() + .name("background-color") + .description("Color used for the background.") + .visible(background::get) + .defaultValue(new SettingColor(25, 25, 25, 50)) + .build() + ); + + private final List modules = new ArrayList<>(); + + private final Color rainbow = new Color(255, 255, 255); + private double rainbowHue1; + private double rainbowHue2; + + private double lastX; + private double emptySpace; + private double prevTextLength; + private Color prevColor = new Color(); + + public ActiveGenyoHud() { + super(INFO); + } + + @Override + public void tick(HudRenderer renderer) { + modules.clear(); + + for (Module module : Modules.get().getActive()) { + if (module instanceof GenyoModule) modules.add(module); + } + + if (modules.isEmpty()) { + if (isInEditor()) { + setSize(renderer.textWidth("Active Modules", shadow.get(), getScale()), renderer.textHeight(shadow.get(), getScale())); + } + return; + } + + modules.sort((e1, e2) -> switch (sort.get()) { + case Alphabetical -> e1.title.compareTo(e2.title); + case Biggest -> Double.compare(getModuleWidth(renderer, e2), getModuleWidth(renderer, e1)); + case Smallest -> Double.compare(getModuleWidth(renderer, e1), getModuleWidth(renderer, e2)); + }); + + double width = 0; + double height = 0; + + for (Module module : modules) { + width = Math.max(width, getModuleWidth(renderer, module)); + height += renderer.textHeight(shadow.get(), getScale()); + } + + setSize(width, height); + } + + @Override + public void render(HudRenderer renderer) { + double x = this.x; + double y = this.y; + + if (modules.isEmpty()) { + if (isInEditor()) { + renderer.text("Active Modules", x, y, WHITE, shadow.get(), getScale()); + } + return; + } + + rainbowHue1 += rainbowSpeed.get() * renderer.delta; + if (rainbowHue1 > 1) rainbowHue1 -= 1; + else if (rainbowHue1 < -1) rainbowHue1 += 1; + + rainbowHue2 = rainbowHue1; + + lastX = x; + emptySpace = renderer.textWidth(" ", shadow.get(), getScale()); + + for (int i = 0; i < modules.size(); i++) { + double offset = alignX(getModuleWidth(renderer, modules.get(i)), alignment.get()); + renderModule(renderer, i, x + offset, y); + + lastX = x + offset; + y += renderer.textHeight(shadow.get(), getScale()); + } + } + + private void renderModule(HudRenderer renderer, int index, double x, double y) { + Module module = modules.get(index); + Color color = flatColor.get(); + + switch (colorMode.get()) { + case Random -> color = module.color; + case Rainbow -> { + rainbowHue2 += rainbowSpread.get(); + int c = java.awt.Color.HSBtoRGB((float) rainbowHue2, rainbowSaturation.get().floatValue(), rainbowBrightness.get().floatValue()); + rainbow.r = Color.toRGBAR(c); + rainbow.g = Color.toRGBAG(c); + rainbow.b = Color.toRGBAB(c); + color = rainbow; + } + } + + renderer.text(module.title, x, y, color, shadow.get(), getScale()); + + double textHeight = renderer.textHeight(shadow.get(), getScale()); + double textLength = renderer.textWidth(module.title, shadow.get(), getScale()); + + if (showKeybind.get() && module.keybind.isSet()) { + String keybindStr = " [" + module.keybind + "]"; + renderer.text(keybindStr, x + textLength, y, moduleInfoColor.get(), shadow.get(), getScale()); + textLength += renderer.textWidth(keybindStr, shadow.get(), getScale()); + } + + if (activeInfo.get()) { + String info = module.getInfoString(); + if (info != null) { + renderer.text(info, x + textLength + emptySpace, y, moduleInfoColor.get(), shadow.get(), getScale()); + textLength += emptySpace + renderer.textWidth(info, shadow.get(), getScale()); + } + } + + double lineStartY = y; + double lineHeight = textHeight; + + if (outlines.get()) { + if (index == 0) { // Render top quad for first item in list + lineStartY -= 2; + lineHeight += 2; + + renderer.quad(x - 2 - outlineWidth.get(), lineStartY - outlineWidth.get(), + textLength + 4 + 2 * outlineWidth.get(), + outlineWidth.get(), prevColor, prevColor, color, color); + } else { // In-between quads are rendered above the current line so don't need for the top + renderer.quad(Math.min(lastX, x) - 2 - outlineWidth.get(), Math.max(lastX, x) == x ? y : y - outlineWidth.get(), + (Math.max(lastX, x) - 2) - (Math.min(lastX, x) - 2 - outlineWidth.get()), outlineWidth.get(), + prevColor, prevColor, color, color); // Left in-between quad + + renderer.quad(Math.min(lastX + prevTextLength, x + textLength) + 2, Math.min(lastX + prevTextLength, x + textLength) == x + textLength ? y : y - outlineWidth.get(), + (Math.max(lastX + prevTextLength, x + textLength) + 2 + outlineWidth.get()) - (Math.min(lastX + prevTextLength, x + textLength) + 2), outlineWidth.get(), + prevColor, prevColor, color, color); // Right in-between quad + } + + if (index == modules.size() - 1) { // Render bottom quad for last item in list + lineHeight += 2; + + renderer.quad(x - 2 - outlineWidth.get(), lineStartY + lineHeight, + textLength + 4 + 2 * outlineWidth.get(), outlineWidth.get(), + prevColor, prevColor, color, color); + } + + // Left side quad + renderer.quad(x - 2 - outlineWidth.get(), lineStartY, outlineWidth.get(), lineHeight, + prevColor, prevColor, color, color); + + // Right side quad + renderer.quad(x + textLength + 2, lineStartY, outlineWidth.get(), lineHeight, + prevColor, prevColor, color, color); + } + + if (background.get()) { + renderer.quad( x - 2, lineStartY, textLength + 4, lineHeight, backgroundColor.get()); + } + + prevTextLength = textLength; + prevColor = color; + } + + private double getModuleWidth(HudRenderer renderer, Module module) { + double width = renderer.textWidth(module.title, shadow.get(), getScale()); + + if (showKeybind.get() && module.keybind.isSet()) { + width += renderer.textWidth(" [" + module.keybind + "]", shadow.get(), getScale()); + } + + if (activeInfo.get()) { + String info = module.getInfoString(); + if (info != null) width += renderer.textWidth(" ", shadow.get(), getScale()) + renderer.textWidth(info, shadow.get(), getScale()); + } + + return width; + } + + private double getScale() { + return customScale.get() ? scale.get() : Hud.get().getTextScale(); + } + + public enum Sort { + Alphabetical, + Biggest, + Smallest + } + + public enum ColorMode { + Flat, + Random, + Rainbow + } + + public enum Background { + None, + Block, + Text + } + +} diff --git a/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java b/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java index b1d4ae0..55bf66c 100644 --- a/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java +++ b/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java @@ -1,12 +1,13 @@ package com.genyo.addon.hud; import com.genyo.addon.GenyoAddon; +import com.genyo.addon.utils.GInvUtils; import com.genyo.addon.utils.HudUtils; -import com.genyo.addon.utils.InventoryUtils; import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.hud.HudElement; import meteordevelopment.meteorclient.systems.hud.HudElementInfo; import meteordevelopment.meteorclient.systems.hud.HudRenderer; +import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -105,7 +106,8 @@ public void render(HudRenderer renderer) { for (int i = 0; i < itemsLength; i++) { Item item = items.get().get(i); - ItemStack itemStack = new ItemStack(item, InventoryUtils.find(item).count()); + //ItemStack itemStack = new ItemStack(item, GInvUtils.find(item).count(); + ItemStack itemStack = new ItemStack(item, InvUtils.find(item).count()); int scaleOffset = (int) (getScale() * 10); int intScale = (int) (getScale()); diff --git a/src/main/java/com/genyo/addon/imixins/IClientPlayNetworkHandler.java b/src/main/java/com/genyo/addon/imixins/IClientPlayNetworkHandler.java new file mode 100644 index 0000000..1d56b89 --- /dev/null +++ b/src/main/java/com/genyo/addon/imixins/IClientPlayNetworkHandler.java @@ -0,0 +1,8 @@ +package com.genyo.addon.imixins; + +import net.minecraft.network.packet.Packet; + +@IMixin +public interface IClientPlayNetworkHandler { + void sendQuietPacket(final Packet packet); +} diff --git a/src/main/java/com/genyo/addon/imixins/IClientPlayerEntity.java b/src/main/java/com/genyo/addon/imixins/IClientPlayerEntity.java new file mode 100644 index 0000000..968d0d4 --- /dev/null +++ b/src/main/java/com/genyo/addon/imixins/IClientPlayerEntity.java @@ -0,0 +1,9 @@ +package com.genyo.addon.imixins; + +@IMixin +public interface IClientPlayerEntity { + + float genyo_addon$getLastSpoofedYaw(); + + float genyo_addon$getLastSpoofedPitch(); +} diff --git a/src/main/java/com/genyo/addon/imixins/IMixin.java b/src/main/java/com/genyo/addon/imixins/IMixin.java new file mode 100644 index 0000000..b8d53bf --- /dev/null +++ b/src/main/java/com/genyo/addon/imixins/IMixin.java @@ -0,0 +1,11 @@ +package com.genyo.addon.imixins; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface IMixin { +} diff --git a/src/main/java/com/genyo/addon/managers/Managers.java b/src/main/java/com/genyo/addon/managers/Managers.java index 8f2174b..d00fd61 100644 --- a/src/main/java/com/genyo/addon/managers/Managers.java +++ b/src/main/java/com/genyo/addon/managers/Managers.java @@ -1,5 +1,17 @@ package com.genyo.addon.managers; +import com.genyo.addon.managers.anticheat.AntiCheatManager; +import com.genyo.addon.managers.combat.CombatManager; +import com.genyo.addon.managers.combat.TotemManager; +import com.genyo.addon.managers.network.GDTogglerManager; +import com.genyo.addon.managers.network.NetworkManager; +import com.genyo.addon.managers.player.InteractionManager; +import com.genyo.addon.managers.player.InventoryManager; +import com.genyo.addon.managers.player.MovementManager; +import com.genyo.addon.managers.player.PositionManager; +import com.genyo.addon.managers.player.rotation.RotationManager; +import com.genyo.addon.managers.world.BlockManager; +import com.genyo.addon.managers.world.tick.TickManager; import com.genyo.addon.render.Render3DEngine; import meteordevelopment.meteorclient.MeteorClient; @@ -7,10 +19,31 @@ public class Managers { public static final CombatManager COMBAT = new CombatManager(); public static final Render3DEngine ENGINE3D = new Render3DEngine(); + public static final BlockManager BLOCK = new BlockManager(); + public static final InventoryManager INVENTORY = new InventoryManager(); + public static final NetworkManager NETWORK = new NetworkManager(); + public static final TotemManager TOTEM = new TotemManager(); + public static final InteractionManager INTERACT = new InteractionManager(); + public static final MovementManager MOVEMENT = new MovementManager(); + public static final RotationManager ROTATION = new RotationManager(); + public static final PositionManager POSITION = new PositionManager(); + public static final AntiCheatManager ANTICHEAT = new AntiCheatManager(); + public static final TickManager TICK = new TickManager(); public static void subscribe() { MeteorClient.EVENT_BUS.subscribe(COMBAT); MeteorClient.EVENT_BUS.subscribe(ENGINE3D); + MeteorClient.EVENT_BUS.subscribe(BLOCK); + MeteorClient.EVENT_BUS.subscribe(INVENTORY); + MeteorClient.EVENT_BUS.subscribe(NETWORK); + MeteorClient.EVENT_BUS.subscribe(TOTEM); + MeteorClient.EVENT_BUS.subscribe(MOVEMENT); + MeteorClient.EVENT_BUS.subscribe(INTERACT); + MeteorClient.EVENT_BUS.subscribe(new GDTogglerManager()); + MeteorClient.EVENT_BUS.subscribe(ROTATION); + MeteorClient.EVENT_BUS.subscribe(POSITION); + MeteorClient.EVENT_BUS.subscribe(ANTICHEAT); + MeteorClient.EVENT_BUS.subscribe(TICK); } } diff --git a/src/main/java/com/genyo/addon/managers/anticheat/AntiCheatManager.java b/src/main/java/com/genyo/addon/managers/anticheat/AntiCheatManager.java new file mode 100644 index 0000000..6f72bad --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/anticheat/AntiCheatManager.java @@ -0,0 +1,74 @@ +package com.genyo.addon.managers.anticheat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.utils.GenyoChatUtils; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.player.PlayerPosition; +import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; +import net.minecraft.util.math.Vec3d; + +import java.util.Arrays; + +public class AntiCheatManager { + + private SetbackData lastSetback; + + private final int[] transactions = new int[4]; + private int index; + private boolean isGrim; + + public AntiCheatManager() { + Arrays.fill(transactions, -1); + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) { + if (event.packet instanceof CommonPingS2CPacket packet) + { + if (index > 3) return; + + final int uid = packet.getParameter(); + transactions[index] = uid; + ++index; + if (index == 4) grimCheck(); + } else if (event.packet instanceof PlayerPositionLookS2CPacket packet) { + Vec3d oldPos = packet.change().position(); + lastSetback = new SetbackData(new Vec3d(oldPos.getX(), oldPos.getY(), oldPos.getZ()), + System.currentTimeMillis(), packet.teleportId()); + } + } + + @EventHandler + public void onDisconnect(final DisconnectEvent event) { + Arrays.fill(transactions, -1); + index = 0; + isGrim = false; + } + + private void grimCheck() + { + for (int i = 0; i < 4; ++i) + { + if (transactions[i] != -i) + { + break; + } + } + isGrim = true; + GenyoChatUtils.sendInfo("Server is running GrimAC"); + } + + public boolean isGrim() + { + return isGrim; + } + + public boolean hasPassed(final long timeMS) + { + return lastSetback != null && lastSetback.timeSince() >= timeMS; + } + +} diff --git a/src/main/java/com/genyo/addon/managers/anticheat/SetbackData.java b/src/main/java/com/genyo/addon/managers/anticheat/SetbackData.java new file mode 100644 index 0000000..3ec2488 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/anticheat/SetbackData.java @@ -0,0 +1,11 @@ +package com.genyo.addon.managers.anticheat; + +import net.minecraft.util.math.Vec3d; + +public record SetbackData(Vec3d position, long timeMS, int teleportID) +{ + public long timeSince() + { + return System.currentTimeMillis() - timeMS; + } +} diff --git a/src/main/java/com/genyo/addon/managers/CombatManager.java b/src/main/java/com/genyo/addon/managers/combat/CombatManager.java similarity index 95% rename from src/main/java/com/genyo/addon/managers/CombatManager.java rename to src/main/java/com/genyo/addon/managers/combat/CombatManager.java index e358051..d726d5d 100644 --- a/src/main/java/com/genyo/addon/managers/CombatManager.java +++ b/src/main/java/com/genyo/addon/managers/combat/CombatManager.java @@ -1,4 +1,4 @@ -package com.genyo.addon.managers; +package com.genyo.addon.managers.combat; import com.genyo.addon.events.TotemPopEvent; import com.genyo.addon.events.UnderCombatEvent; @@ -8,7 +8,6 @@ import meteordevelopment.orbit.EventHandler; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityStatuses; -import net.minecraft.entity.decoration.EndCrystalEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; diff --git a/src/main/java/com/genyo/addon/managers/combat/TotemManager.java b/src/main/java/com/genyo/addon/managers/combat/TotemManager.java new file mode 100644 index 0000000..0de24d5 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/combat/TotemManager.java @@ -0,0 +1,97 @@ +package com.genyo.addon.managers.combat; + +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.events.entity.EntityDeathEvent; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityStatuses; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class TotemManager { + + // + private final ConcurrentMap totems = new ConcurrentHashMap<>(); + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) + { + if (mc.world == null) return; + + if (event.packet instanceof EntityStatusS2CPacket packet + && packet.getStatus() == EntityStatuses.USE_TOTEM_OF_UNDYING) + { + Entity entity = packet.getEntity(mc.world); + if (entity != null && entity.isAlive()) + { + if (totems.containsKey(entity.getUuid())) + { + totems.replace(entity.getUuid(), new TotemData(System.currentTimeMillis(), + totems.get(entity.getUuid()).getPops() + 1)); + } + else + { + totems.put(entity.getUuid(), new TotemData(System.currentTimeMillis(), 1)); + } + } + } + } + + @EventHandler(priority = Integer.MIN_VALUE) + public void onRemoveEntity(EntityDeathEvent event) + { + totems.remove(event.entity.getUuid()); + } + + @EventHandler + public void onDisconnect(DisconnectEvent event) + { + totems.clear(); + } + + /** + * Returns the number of totems popped by the given {@link PlayerEntity} + * + * @param entity + * @return Ehe number of totems popped by the player + */ + public int getTotems(Entity entity) + { + return totems.getOrDefault(entity.getUuid(), new TotemData(0, 0)).getPops(); + } + + public long getLastPopTime(Entity entity) + { + return totems.getOrDefault(entity.getUuid(), new TotemData(-1, 0)).getLastPopTime(); + } + + public static class TotemData + { + private final long lastPopTime; + private final int pops; + + public TotemData(long lastPopTime, int pops) + { + this.lastPopTime = lastPopTime; + this.pops = pops; + } + + public int getPops() + { + return pops; + } + + public long getLastPopTime() + { + return lastPopTime; + } + } + +} diff --git a/src/main/java/com/genyo/addon/managers/network/GDTogglerManager.java b/src/main/java/com/genyo/addon/managers/network/GDTogglerManager.java new file mode 100644 index 0000000..ab32369 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/network/GDTogglerManager.java @@ -0,0 +1,19 @@ +package com.genyo.addon.managers.network; + +import com.genyo.addon.modules.misc.GenyoDiscord; +import com.genyo.addon.utils.GenyoChatUtils; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.orbit.EventHandler; + +public class GDTogglerManager { + + @EventHandler + private void onTick(TickEvent.Post event) { + if (!Modules.get().isActive(GenyoDiscord.class)) { + Modules.get().get(GenyoDiscord.class).toggle(); + GenyoChatUtils.sendInfo("Why would you turn it off?"); + } + } + +} diff --git a/src/main/java/com/genyo/addon/managers/network/NetworkManager.java b/src/main/java/com/genyo/addon/managers/network/NetworkManager.java new file mode 100644 index 0000000..d441c48 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/network/NetworkManager.java @@ -0,0 +1,199 @@ +package com.genyo.addon.managers.network; + +import com.genyo.addon.events.network.ConnectScreenEvent; +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.mixin.accessor.AccessorClientWorld; +import com.genyo.addon.imixins.IClientPlayNetworkHandler; +import com.genyo.addon.utils.math.PerSecondCounter; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.network.*; +import net.minecraft.network.listener.ServerPlayPacketListener; +import net.minecraft.network.packet.Packet; + +import java.util.HashSet; +import java.util.Set; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class NetworkManager { + + private static final Set> PACKET_CACHE = new HashSet<>(); + + private ServerAddress address; + private ServerInfo info; + + private final PerSecondCounter outgoingCounter = new PerSecondCounter(); + private final PerSecondCounter incomingCounter = new PerSecondCounter(); + + @EventHandler + public void onConnectScreen(ConnectScreenEvent event) + { + address = event.address; + info = event.info; + } + + @EventHandler + public void onDisconnect(DisconnectEvent event) + { + PACKET_CACHE.clear(); + } + + @EventHandler + public void onPacketSend(PacketEvent.Send event) + { + outgoingCounter.updateCounter(); + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) + { + incomingCounter.updateCounter(); + } + + public void connect(final ServerAddress address, final ServerInfo info) + { + if (mc.getNetworkHandler() == null) + { + return; + } + mc.getNetworkHandler().getConnection().connect(address.getAddress(), address.getPort(), + new ClientLoginNetworkHandler(mc.getNetworkHandler().getConnection(), mc, info, null, false, null, null, null)); + } + + public void sendQuietPacket(final Packet p) + { + if (mc.getNetworkHandler() != null) + { + PACKET_CACHE.add(p); + ((IClientPlayNetworkHandler) mc.getNetworkHandler()).sendQuietPacket(p); + } + } + + /** + * @param p + */ + public void sendPacket(final Packet p) + { + if (mc.getNetworkHandler() != null) + { + PACKET_CACHE.add(p); + mc.getNetworkHandler().sendPacket(p); + } + } + + /** + * @param p + */ + public void sendSequencedPacket(final SequencedPacketCreator p) + { + if (mc.world != null) + { + PendingUpdateManager updater = + ((AccessorClientWorld) mc.world).hookGetPendingUpdateManager().incrementSequence(); + try + { + int i = updater.getSequence(); + Packet packet = p.predict(i); + sendPacket(packet); + } + catch (Throwable e) + { + e.printStackTrace(); + if (updater != null) + { + try + { + updater.close(); + } + catch (Throwable e1) + { + e1.printStackTrace(); + e.addSuppressed(e1); + } + } + throw e; + } + if (updater != null) + { + updater.close(); + } + } + } + + /** + * @return + */ + public int getClientLatency() + { + if (mc.getNetworkHandler() != null) + { + final PlayerListEntry playerEntry = + mc.getNetworkHandler().getPlayerListEntry(mc.player.getGameProfile().getId()); + if (playerEntry != null) + { + return playerEntry.getLatency(); + } + } + return 0; + } + + public ServerAddress getAddress() + { + return address; + } + + public void setAddress(ServerAddress address) + { + this.address = address; + } + + public ServerInfo getInfo() + { + return info; + } + + public void setInfo(ServerInfo info) + { + this.info = info; + } + + public boolean isCrystalPvpCC() + { + return getServerIp().contains("crystalpvp.cc"); + } + + public boolean is2b2t() + { + return getServerIp().contains("2b2t.org"); + } + + public int getOutgoingPPS() + { + return outgoingCounter.getPerSecond(); + } + + public int getIncomingPPS() + { + return incomingCounter.getPerSecond(); + } + + public String getServerIp() + { + if (info != null) + { + return info.address; + } + return "Singleplayer"; + } + + /** + * @param p + * @return + */ + public boolean isCached(Packet p) + { + return PACKET_CACHE.contains(p); + } + +} diff --git a/src/main/java/com/genyo/addon/managers/player/InteractionManager.java b/src/main/java/com/genyo/addon/managers/player/InteractionManager.java new file mode 100644 index 0000000..bcdf854 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/InteractionManager.java @@ -0,0 +1,384 @@ +package com.genyo.addon.managers.player; + +import com.genyo.addon.managers.Managers; +import com.genyo.addon.utils.player.MovementUtil; +import com.genyo.addon.utils.player.RotationUtil; +import com.genyo.addon.utils.world.SneakBlocks; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; + +import java.util.HashSet; +import java.util.Set; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class InteractionManager { + + public boolean placeBlock(final BlockPos pos, + final int slot, + final boolean strictDirection, + final boolean clientSwing, + final RotationCallback rotationCallback) + { + return placeBlock(pos, slot, strictDirection, clientSwing, rotationCallback, false); + } + + public boolean placeBlock(final BlockPos pos, + final int slot, + final boolean strictDirection, + final boolean clientSwing, + final RotationCallback rotationCallback, + final boolean airPlace) + { + Direction direction = getInteractDirectionInternal(pos, strictDirection); + /*if (airPlace || AirPlaceModule.getInstance().isEnabled() && direction == null) + { + direction = Direction.DOWN; + return placeBlock(pos, direction, slot, clientSwing, AnticheatModule.getInstance().isGrim(), rotationCallback); + }*/ + if (direction == null) + { + return false; + } + final BlockPos neighbor = pos.offset(direction.getOpposite()); + return placeBlock(neighbor, direction, slot, clientSwing, false, rotationCallback); + } + + public boolean placeBlock(final BlockPos pos, + final int slot, + final boolean strictDirection, + final boolean clientSwing, + final boolean packet, + final RotationCallback rotationCallback) + { + return placeBlock(pos, slot, strictDirection, clientSwing, packet, false, rotationCallback); + } + + public boolean placeBlock(final BlockPos pos, + final int slot, + final boolean strictDirection, + final boolean clientSwing, + final boolean packet, + final boolean airPlace, + final RotationCallback rotationCallback) + { + Direction direction = getInteractDirectionInternal(pos, strictDirection); + /*if (airPlace || AirPlaceModule.getInstance().isEnabled() && direction == null) + { + direction = Direction.DOWN; + return placeBlock(pos, direction, slot, clientSwing, AnticheatModule.getInstance().isGrim(), rotationCallback); + }*/ + if (direction == null) + { + return false; + } + final BlockPos neighbor = pos.offset(direction.getOpposite()); + return placeBlock(neighbor, direction, slot, clientSwing, false, packet, rotationCallback); + } + + public boolean placeBlock(final BlockPos pos, + final Direction direction, + final int slot, + final boolean clientSwing, + final boolean grimAirPlace, + final boolean packet, + final RotationCallback rotationCallback) + { + Vec3d hitVec = pos.toCenterPos().add(new Vec3d(direction.getUnitVector()).multiply(0.5)); + return placeBlock(new BlockHitResult(hitVec, direction, pos, false), + slot, clientSwing, grimAirPlace, packet, rotationCallback); + } + + public boolean placeBlock(final BlockPos pos, + final Direction direction, + final int slot, + final boolean clientSwing, + final boolean grimAirPlace, + final RotationCallback rotationCallback) + { + Vec3d hitVec = pos.toCenterPos().add(new Vec3d(direction.getUnitVector()).multiply(0.5)); + return placeBlock(new BlockHitResult(hitVec, direction, pos, false), + slot, clientSwing, grimAirPlace, rotationCallback); + } + + public boolean placeBlock(final BlockHitResult hitResult, + final int slot, + final boolean clientSwing, + final boolean grimAirPlace, + final boolean packet, + final RotationCallback rotationCallback) + { + final boolean isSpoofing = slot != Managers.INVENTORY.getServerSlot(); + if (isSpoofing) + { + Managers.INVENTORY.setSlot(slot); + // mc.player.getInventory().selectedSlot = slot; + } + + if (grimAirPlace) + { + Managers.NETWORK.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); + } + + final boolean isRotating = rotationCallback != null; + if (isRotating) + { + float[] angles = RotationUtil.getRotationsTo(mc.player.getEyePos(), hitResult.getPos()); + rotationCallback.handleRotation(true, angles); + } + + final boolean result = placeBlockImmediately(hitResult, grimAirPlace ? Hand.OFF_HAND : Hand.MAIN_HAND, clientSwing, packet); + if (isRotating) + { + float[] angles = RotationUtil.getRotationsTo(mc.player.getEyePos(), hitResult.getPos()); + rotationCallback.handleRotation(false, angles); + } + + if (grimAirPlace) + { + Managers.NETWORK.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); + } + + if (isSpoofing) + { + Managers.INVENTORY.syncToClient(); + //mc.player.getInventory().selectedSlot = previousSlot; + } + + return result; + } + + public boolean placeBlock(final BlockHitResult hitResult, + final int slot, + final boolean clientSwing, + final boolean grimAirPlace, + final RotationCallback rotationCallback) + { + final boolean isSpoofing = slot != Managers.INVENTORY.getServerSlot(); + if (isSpoofing) + { + Managers.INVENTORY.setSlot(slot); + // mc.player.getInventory().selectedSlot = slot; + } + + if (grimAirPlace) + { + Managers.NETWORK.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); + } + + final boolean isRotating = rotationCallback != null; + if (isRotating) + { + float[] angles = RotationUtil.getRotationsTo(mc.player.getEyePos(), hitResult.getPos()); + rotationCallback.handleRotation(true, angles); + } + + final boolean result = placeBlockImmediately(hitResult, grimAirPlace ? Hand.OFF_HAND : Hand.MAIN_HAND, clientSwing, true); + if (isRotating) + { + float[] angles = RotationUtil.getRotationsTo(mc.player.getEyePos(), hitResult.getPos()); + rotationCallback.handleRotation(false, angles); + } + + if (grimAirPlace) + { + Managers.NETWORK.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); + } + + if (isSpoofing) + { + Managers.INVENTORY.syncToClient(); + //mc.player.getInventory().selectedSlot = previousSlot; + } + + return result; + } + + public boolean placeBlockImmediately(final BlockHitResult result, + final Hand hand, + final boolean clientSwing, + final boolean packet) + { + final BlockState state = mc.world.getBlockState(result.getBlockPos()); + final boolean shouldSneak = SneakBlocks.isSneakBlock(state) && !mc.player.isSneaking(); + if (shouldSneak) + { + Managers.MOVEMENT.setPacketSneaking(true); + MovementUtil.applySneak(); + } + final ActionResult actionResult = packet ? placeBlockPacket(result, hand) : placeBlockInternally(result, hand); + if (actionResult.isAccepted()) + { + if (clientSwing) + { + mc.player.swingHand(Hand.MAIN_HAND); + } + else + { + Managers.NETWORK.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + } + } + if (shouldSneak) + { + Managers.MOVEMENT.setPacketSneaking(false); + } + return actionResult.isAccepted(); + } + + private ActionResult placeBlockInternally(final BlockHitResult hitResult, + final Hand hand) + { + return mc.interactionManager.interactBlock(mc.player, hand, hitResult); + // Managers.NETWORK.sendSequencedPacket(sequence -> new PlayerInteractBlockC2SPacket(Hand.MAIN_HAND, hitResult, sequence)); + // return ((AccessorClientPlayerInteractionManager) mc.interactionManager).hookInteractBlockInternal(mc.player, Hand.MAIN_HAND, hitResult); + } + + public ActionResult placeBlockPacket(final BlockHitResult hitResult, + final Hand hand) + { + Managers.NETWORK.sendSequencedPacket(id -> new PlayerInteractBlockC2SPacket(hand, hitResult, id)); + return ActionResult.SUCCESS; + } + + public Direction getInteractDirection(final BlockPos blockPos, final boolean strictDirection) + { + Direction direction = getInteractDirectionInternal(blockPos, strictDirection); + return direction == null ? Direction.UP : direction; + } + + /** + * @param blockPos + * @param strictDirection + * @return + */ + public Direction getInteractDirectionInternal(final BlockPos blockPos, final boolean strictDirection) + { + Set validDirections = getPlaceDirectionsNCP(mc.player.getEyePos(), blockPos.toCenterPos()); + Direction interactDirection = null; + for (final Direction direction : Direction.values()) + { + final BlockState state = mc.world.getBlockState(blockPos.offset(direction)); + if (state.isAir() || !state.getFluidState().isEmpty()) + { + continue; + } + + if (state.getBlock() == Blocks.ANVIL || state.getBlock() == Blocks.CHIPPED_ANVIL + || state.getBlock() == Blocks.DAMAGED_ANVIL) + { + continue; + } + + if (strictDirection && !validDirections.contains(direction.getOpposite())) + { + continue; + } + interactDirection = direction; + break; + } + if (interactDirection == null) + { + return null; + } + return interactDirection.getOpposite(); + } + + public Direction getPlaceDirectionNCP(BlockPos blockPos, boolean visible) + { + Vec3d eyePos = new Vec3d(mc.player.getX(), mc.player.getY() + mc.player.getStandingEyeHeight(), mc.player.getZ()); + if (blockPos.getX() == eyePos.getX() && blockPos.getY() == eyePos.getY() && blockPos.getZ() == eyePos.getZ()) + { + return Direction.DOWN; + } + else + { + Set ncpDirections = getPlaceDirectionsNCP(eyePos, blockPos.toCenterPos()); + for (Direction dir : ncpDirections) + { + if (visible && !mc.world.isAir(blockPos.offset(dir))) + { + continue; + } + return dir; + } + } + return Direction.UP; + } + + public Set getPlaceDirectionsNCP(Vec3d eyePos, Vec3d blockPos) + { + return getPlaceDirectionsNCP(eyePos.x, eyePos.y, eyePos.z, blockPos.x, blockPos.y, blockPos.z); + } + + public Set getPlaceDirectionsNCP(final double x, final double y, final double z, + final double dx, final double dy, final double dz) + { + // directly from NCP src + final double xdiff = x - dx; + final double ydiff = y - dy; + final double zdiff = z - dz; + final Set dirs = new HashSet<>(6); + if (ydiff > 0.5) + { + dirs.add(Direction.UP); + } + else if (ydiff < -0.5) + { + dirs.add(Direction.DOWN); + } + else + { + dirs.add(Direction.UP); + dirs.add(Direction.DOWN); + } + if (xdiff > 0.5) + { + dirs.add(Direction.EAST); + } + else if (xdiff < -0.5) + { + dirs.add(Direction.WEST); + } + else + { + dirs.add(Direction.EAST); + dirs.add(Direction.WEST); + } + if (zdiff > 0.5) + { + dirs.add(Direction.SOUTH); + } + else if (zdiff < -0.5) + { + dirs.add(Direction.NORTH); + } + else + { + dirs.add(Direction.SOUTH); + dirs.add(Direction.NORTH); + } + return dirs; + } + + /** + * Checks if the block is within our "eye range" + * You can't place blocks above your head for any direction other than DOWN + * + * @param pos the block position + * @return if the block pos is in range of our eye y coordinate + */ + public boolean isInEyeRange(final BlockPos pos) + { + return pos.getY() > mc.player.getY() + mc.player.getStandingEyeHeight(); + } + +} diff --git a/src/main/java/com/genyo/addon/managers/player/InventoryManager.java b/src/main/java/com/genyo/addon/managers/player/InventoryManager.java new file mode 100644 index 0000000..466b2bc --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/InventoryManager.java @@ -0,0 +1,390 @@ +package com.genyo.addon.managers.player; + +import com.genyo.addon.events.entity.EntityDeathEvent; +import com.genyo.addon.events.network.ItemDesyncEvent; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.mixin.accessor.AccessorBundlePacket; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.google.common.collect.Lists; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; +import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket; +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; +import net.minecraft.network.packet.s2c.play.BundleS2CPacket; +import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; +import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.util.collection.DefaultedList; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class InventoryManager { + + private final List swapData = new CopyOnWriteArrayList<>(); + + // The serverside selected hotbar slot. + private int slot; + + @EventHandler + public void onPacketSend(final PacketEvent.Send event) + { + if (event.packet instanceof UpdateSelectedSlotC2SPacket packet) + { + final int packetSlot = packet.getSelectedSlot(); + if (!PlayerInventory.isValidHotbarIndex(packetSlot) || slot == packetSlot) + { + event.cancel(); + return; + } + slot = packetSlot; + } + } + + @EventHandler + public void onPacketReceive(final PacketEvent.Receive event) + { + if (event.packet instanceof UpdateSelectedSlotS2CPacket packet) + { + slot = packet.slot(); + } + + // retarded packets from grim we can ignore + if (event.packet instanceof BundleS2CPacket packet) + { + List> allowedBundle = new ArrayList<>(); + for (Packet packet1 : packet.getPackets()) + { + if (packet1 instanceof ScreenHandlerSlotUpdateS2CPacket) + { + continue; + } + allowedBundle.add(packet1); + } + ((AccessorBundlePacket) packet).setIterable(allowedBundle); + } + + if (event.packet instanceof ScreenHandlerSlotUpdateS2CPacket packet) + { + int slot = packet.getSlot() - 36; + if (slot < 0 || slot > 8) + { + return; + } + + if (packet.getStack().isEmpty()) + { + return; + } + + for (PreSwapData data : swapData) + { + if (data.getSlot() != slot && data.getStarting() != slot) + { + continue; + } + + ItemStack preStack = data.getPreHolding(slot); + if (!isEqual(preStack, packet.getStack())) + { + event.cancel(); + break; + } + } + } + } + + @EventHandler + public void onItemDesync(ItemDesyncEvent event) + { + if (isDesynced()) + { + event.cancel(); + event.setStack(getServerItem()); + } + } + + @EventHandler + public void onDeath(EntityDeathEvent event) + { + if (event.entity == mc.player) + { + syncToClient(); + } + } + + @EventHandler + public void onTick(TickEvent.Pre event) + { + swapData.removeIf(PreSwapData::isPassedClearTime); + } + + /** + * Sets the server slot via a {@link UpdateSelectedSlotC2SPacket} + * + * @param barSlot the player hotbar slot 0-8 + * @apiNote Method will not do anything if the slot provided is already the server slot + * @see InventoryManager#setSlotForced(int) + */ + public void setSlot(final int barSlot) + { + if (slot != barSlot && PlayerInventory.isValidHotbarIndex(barSlot)) + { + setSlotForced(barSlot); + + final ItemStack[] hotbarCopy = new ItemStack[9]; + for (int i = 0; i < 9; i++) + { + hotbarCopy[i] = mc.player.getInventory().getStack(i); + } + swapData.add(new PreSwapData(hotbarCopy, slot, barSlot)); + } + } + + /** + * Sets the server slot via a click slot + * + * @param barSlot the player hotbar slot 0-8 + */ + public void setSlotAlt(final int barSlot) + { + if (PlayerInventory.isValidHotbarIndex(barSlot)) + { + mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, + barSlot + 36, slot, SlotActionType.SWAP, mc.player); + } + } + + /** + * Sets the server & client slot + * + * @param barSlot the player hotbar slot 0-8 + * @apiNote Method will not do anything if the slot provided is already the server slot + * @see InventoryManager#setSlotForced(int) + * @see InventoryManager#setSlot(int) + */ + public void setClientSlot(final int barSlot) + { + if (mc.player.getInventory().selectedSlot != barSlot + && PlayerInventory.isValidHotbarIndex(barSlot)) + { + mc.player.getInventory().selectedSlot = barSlot; + setSlotForced(barSlot); + } + } + + /** + * Sends a {@link UpdateSelectedSlotC2SPacket} without any slot checks + * + * @param barSlot the player hotbar slot 0-8 + */ + public void setSlotForced(final int barSlot) + { + Managers.NETWORK.sendPacket(new UpdateSelectedSlotC2SPacket(barSlot)); + } + + /** + * Syncs the server slot to the client slot + */ + public void syncToClient() + { + if (isDesynced()) + { + setSlotForced(mc.player.getInventory().selectedSlot); + + for (PreSwapData swapData : swapData) + { + swapData.beginClear(); + } + } + } + + public boolean isDesynced() + { + return mc.player.getInventory().selectedSlot != slot; + } + + // + public void closeScreen() + { + mc.getNetworkHandler().sendPacket(new CloseHandledScreenC2SPacket(mc.player.currentScreenHandler.syncId)); + } + + /** + * @param slot + */ + public int pickupSlot(final int slot) + { + return click(slot, 0, SlotActionType.PICKUP); + } + + public void quickMove(final int slot) + { + click(slot, 0, SlotActionType.QUICK_MOVE); + } + + /** + * @param slot + */ + public void throwSlot(final int slot) + { + click(slot, 0, SlotActionType.THROW); + } + + public int findEmptySlot() + { + for (int i = 9; i < 36; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.isEmpty()) + { + return i; + } + } + return -999; // throw + } + + /** + * @param button + * @param type + */ + public int click(int slot, int button, SlotActionType type) + { + if (slot < 0) + { + return -1; + } + ScreenHandler screenHandler = mc.player.currentScreenHandler; + DefaultedList defaultedList = screenHandler.slots; + int i = defaultedList.size(); + ArrayList list = Lists.newArrayListWithCapacity(i); + for (Slot slot1 : defaultedList) + { + list.add(slot1.getStack().copy()); + } + screenHandler.onSlotClick(slot, button, type, mc.player); + Int2ObjectOpenHashMap int2ObjectMap = new Int2ObjectOpenHashMap<>(); + for (int j = 0; j < i; ++j) + { + ItemStack itemStack2; + ItemStack itemStack = list.get(j); + if (ItemStack.areEqual(itemStack, itemStack2 = defaultedList.get(j).getStack())) continue; + int2ObjectMap.put(j, itemStack2.copy()); + } + mc.player.networkHandler.sendPacket(new ClickSlotC2SPacket(screenHandler.syncId, screenHandler.getRevision(), slot, button, type, screenHandler.getCursorStack().copy(), int2ObjectMap)); + return screenHandler.getRevision(); + } + + public int click2(int slot, int button, SlotActionType type) + { + if (slot < 0) + { + return -1; + } + ScreenHandler screenHandler = mc.player.currentScreenHandler; + DefaultedList defaultedList = screenHandler.slots; + int i = defaultedList.size(); + ArrayList list = Lists.newArrayListWithCapacity(i); + for (Slot slot1 : defaultedList) + { + list.add(slot1.getStack().copy()); + } + // screenHandler.onSlotClick(slot, button, type, mc.player); + Int2ObjectOpenHashMap int2ObjectMap = new Int2ObjectOpenHashMap<>(); + for (int j = 0; j < i; ++j) + { + ItemStack itemStack2; + ItemStack itemStack = list.get(j); + if (ItemStack.areEqual(itemStack, itemStack2 = defaultedList.get(j).getStack())) continue; + int2ObjectMap.put(j, itemStack2.copy()); + } + mc.player.networkHandler.sendPacket(new ClickSlotC2SPacket(screenHandler.syncId, screenHandler.getRevision(), slot, button, type, screenHandler.getCursorStack().copy(), int2ObjectMap)); + return screenHandler.getRevision(); + } + + /** + * @return + */ + public int getServerSlot() + { + return slot; + } + + public int getClientSlot() + { + return mc.player.getInventory().selectedSlot; + } + + /** + * @return + */ + public ItemStack getServerItem() + { + if (mc.player != null && getServerSlot() != -1) + { + return mc.player.getInventory().getStack(getServerSlot()); + } + return null; + } + + private boolean isEqual(ItemStack stack1, ItemStack stack2) + { + return stack1.getItem().equals(stack2.getItem()) && stack1.getName().equals(stack2.getName()); + } + + public static class PreSwapData + { + private final ItemStack[] preHotbar; + + private final int starting; + private final int swapTo; + + private Timer clearTime; + + public PreSwapData(ItemStack[] preHotbar, int start, int swapTo) + { + this.preHotbar = preHotbar; + this.starting = start; + this.swapTo = swapTo; + } + + public void beginClear() + { + clearTime = new CacheTimer(); + clearTime.reset(); + } + + public boolean isPassedClearTime() + { + return clearTime != null && clearTime.passed(300); + } + + public ItemStack getPreHolding(int i) + { + return preHotbar[i]; + } + + public int getStarting() + { + return starting; + } + + public int getSlot() + { + return swapTo; + } + } + +} diff --git a/src/main/java/com/genyo/addon/managers/player/MovementManager.java b/src/main/java/com/genyo/addon/managers/player/MovementManager.java new file mode 100644 index 0000000..6d9effd --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/MovementManager.java @@ -0,0 +1,63 @@ +package com.genyo.addon.managers.player; + +import com.genyo.addon.events.network.PacketSneakingEvent; +import com.genyo.addon.managers.Managers; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; + +import static meteordevelopment.meteorclient.MeteorClient.mc; +import static net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY; +import static net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY; + +public class MovementManager { + + private boolean packetSneaking; + + /** + * @param y + */ + public void setMotionY(double y) + { + mc.player.setVelocity(mc.player.getVelocity().getX(), y, mc.player.getVelocity().getZ()); + } + + /** + * @param x + * @param z + */ + public void setMotionXZ(double x, double z) + { + mc.player.setVelocity(x, mc.player.getVelocity().y, z); + } + + public void setMotionX(double x) + { + mc.player.setVelocity(x, mc.player.getVelocity().y, mc.player.getVelocity().z); + } + + public void setMotionZ(double z) + { + mc.player.setVelocity(mc.player.getVelocity().x, mc.player.getVelocity().y, z); + } + + + public void setPacketSneaking(final boolean packetSneaking) + { + this.packetSneaking = packetSneaking; + if (packetSneaking) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, PRESS_SHIFT_KEY)); + } + else + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, RELEASE_SHIFT_KEY)); + } + } + + @EventHandler + public void onPacketSneak(PacketSneakingEvent event) + { + event.setCancelled(packetSneaking); + } + +} diff --git a/src/main/java/com/genyo/addon/managers/player/PositionManager.java b/src/main/java/com/genyo/addon/managers/player/PositionManager.java new file mode 100644 index 0000000..94a235c --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/PositionManager.java @@ -0,0 +1,220 @@ +package com.genyo.addon.managers.player; + +import com.genyo.addon.managers.Managers; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class PositionManager { + + // + private double x, y, z; + private BlockPos blockPos; + // + private boolean sneaking, sprinting; + // + private boolean onGround; + private boolean horizontalCollision; + + /** + * @param vec3d + */ + public void setPosition(Vec3d vec3d) + { + setPosition(vec3d.getX(), vec3d.getY(), vec3d.getZ()); + } + + public void setPositionAndRotation(double x, double y, double z, float yaw, float pitch) + { + setPositionClient(x, y, z); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full(x, y, z, yaw, pitch, isOnGround(), isCollidingHorizontally())); + } + + /** + * @param x + * @param y + * @param z + */ + public void setPosition(double x, double y, double z) + { + setPositionClient(x, y, z); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(x, y, z, isOnGround(), isCollidingHorizontally())); + } + + /** + * @param x + * @param y + * @param z + */ + public void setPositionClient(double x, double y, double z) + { + if (mc.player.isRiding()) + { + mc.player.getVehicle().setPosition(x, y, z); + return; + } + mc.player.setPosition(x, y, z); + } + + /** + * @param x + * @param z + */ + public void setPositionXZ(double x, double z) + { + setPosition(x, y, z); + } + + /** + * @param y + */ + public void setPositionY(double y) + { + setPosition(x, y, z); + } + + /** + * @return + */ + public Vec3d getPos() + { + return new Vec3d(getX(), getY(), getZ()); + } + + /** + * @return + */ + public Vec3d getEyePos() + { + return getPos().add(0.0, mc.player.getStandingEyeHeight(), 0.0); + } + + /** + * @param tickDelta + * @return + */ + public final Vec3d getCameraPosVec(float tickDelta) + { + double d = MathHelper.lerp(tickDelta, mc.player.prevX, getX()); + double e = MathHelper.lerp(tickDelta, mc.player.prevY, getY()) + + (double) mc.player.getStandingEyeHeight(); + double f = MathHelper.lerp(tickDelta, mc.player.prevZ, getZ()); + return new Vec3d(d, e, f); + } + + /** + * @param entity + * @return + */ + public double squaredDistanceTo(Entity entity) + { + float f = (float) (getX() - entity.getX()); + float g = (float) (getY() - entity.getY()); + float h = (float) (getZ() - entity.getZ()); + return MathHelper.squaredMagnitude(f, g, h); + } + + /** + * @param entity + * @return + */ + public double squaredReachDistanceTo(Entity entity) + { + Vec3d cam = getCameraPosVec(1.0f); + float f = (float) (cam.getX() - entity.getX()); + float g = (float) (cam.getY() - entity.getY()); + float h = (float) (cam.getZ() - entity.getZ()); + return MathHelper.squaredMagnitude(f, g, h); + } + + /** + * @param event + */ + @EventHandler + public void onPacketSend(PacketEvent.Send event) + { + if (mc.player != null && mc.world != null) + { + if (event.packet instanceof PlayerMoveC2SPacket packet) + { + onGround = packet.isOnGround(); + horizontalCollision = packet.horizontalCollision(); + if (packet.changesPosition()) + { + x = packet.getX(x); + y = packet.getY(y); + z = packet.getZ(z); + blockPos = BlockPos.ofFloored(x, y, z); + } + } + else if (event.packet instanceof ClientCommandC2SPacket packet) + { + switch (packet.getMode()) + { + case START_SPRINTING -> sprinting = true; + case STOP_SPRINTING -> sprinting = false; + case PRESS_SHIFT_KEY -> sneaking = true; + case RELEASE_SHIFT_KEY -> sneaking = false; + } + } + } + } + + public double getX() + { + return x; + } + + public double getY() + { + return y; + } + + public double getZ() + { + return z; + } + + /** + * @return + */ + public BlockPos getBlockPos() + { + return blockPos; + } + + /** + * @return + */ + public boolean isSneaking() + { + return sneaking; + } + + /** + * @return + */ + public boolean isSprinting() + { + return sprinting; + } + + /** + * @return + */ + public boolean isOnGround() + { + return onGround; + } + + public boolean isCollidingHorizontally() { + return horizontalCollision; + } +} diff --git a/src/main/java/com/genyo/addon/managers/player/RotationCallback.java b/src/main/java/com/genyo/addon/managers/player/RotationCallback.java new file mode 100644 index 0000000..3c685d3 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/RotationCallback.java @@ -0,0 +1,12 @@ +package com.genyo.addon.managers.player; + +public interface RotationCallback { + + /** + * Handles a rotation for this interaction + * + * @param state if this callback is called before or after the interaction is completed + */ + void handleRotation(final boolean state, final float[] angles); + +} diff --git a/src/main/java/com/genyo/addon/managers/player/rotation/Rotation.java b/src/main/java/com/genyo/addon/managers/player/rotation/Rotation.java new file mode 100644 index 0000000..25d43fb --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/rotation/Rotation.java @@ -0,0 +1,57 @@ +package com.genyo.addon.managers.player.rotation; + +public class Rotation { + + private final int priority; + private float yaw, pitch; + private boolean snap; + + public Rotation(int priority, float yaw, float pitch, boolean snap) + { + this.priority = priority; + this.yaw = yaw; + this.pitch = pitch; + this.snap = snap; + } + + public Rotation(int priority, float yaw, float pitch) + { + this(priority, yaw, pitch, false); + } + + public int getPriority() + { + return priority; + } + + public void setYaw(float yaw) + { + this.yaw = yaw; + } + + public void setPitch(float pitch) + { + this.pitch = pitch; + } + + public float getYaw() + { + return yaw; + } + + public float getPitch() + { + return pitch; + } + + public void setSnap(boolean snap) + { + this.snap = snap; + } + + public boolean isSnap() + { + return snap; + } + +} diff --git a/src/main/java/com/genyo/addon/managers/player/rotation/RotationManager.java b/src/main/java/com/genyo/addon/managers/player/rotation/RotationManager.java new file mode 100644 index 0000000..185d9fa --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/player/rotation/RotationManager.java @@ -0,0 +1,329 @@ +package com.genyo.addon.managers.player.rotation; + +import com.genyo.addon.events.StageEvent; +import com.genyo.addon.events.network.MovementPacketsEvent; +import com.genyo.addon.events.network.PlayerTickEvent; +import com.genyo.addon.events.network.PlayerUpdateEvent; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.imixins.IClientPlayerEntity; +import com.genyo.addon.utils.player.PlayerUtil; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import static java.lang.Integer.MAX_VALUE; +import static java.lang.Integer.MIN_VALUE; +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class RotationManager { + + private final List requests = new CopyOnWriteArrayList<>(); + // Relevant rotation values + private float serverYaw, serverPitch, lastServerYaw, lastServerPitch, prevJumpYaw, prevYaw, prevPitch; + boolean rotate; + + // The current in use rotation + private Rotation rotation; + private int rotateTicks; + + // Sprint jump fix for webs + private boolean webJumpFix; + private boolean preJumpFix; + + @EventHandler + public void onPacketSend(PacketEvent.Send event) + { + if (mc.player == null || mc.world == null) + { + return; + } + if (event.packet instanceof PlayerMoveC2SPacket packet && packet.changesLook()) + { + float packetYaw = packet.getYaw(0.0f); + float packetPitch = packet.getPitch(0.0f); + serverYaw = packetYaw; + serverPitch = packetPitch; + } + } + + @EventHandler(priority = MIN_VALUE) + public void onPlayerTick(PlayerTickEvent event) + { + webJumpFix = PlayerUtil.inWeb(1.0); + + if (requests.isEmpty()) + { + rotation = null; + return; + } + Rotation request = getRotationRequest(); + /*if (request == null) + { + if (isDoneRotating()) + { + rotation = null; + return; + } + } + else + {*/ + rotation = request; + //} + // fixes flags for aim % 360 + // GCD implementation maybe? + if (rotation == null) + { + return; + } + rotateTicks = 0; + rotate = true; + } + + @EventHandler + public void onMovementPackets(MovementPacketsEvent event) { + if (rotation != null) { + + if (rotate) { + removeRotation(rotation); + event.cancel(); + event.yaw = rotation.getYaw(); + event.pitch = rotation.getPitch(); + rotate = false; + } + + if (rotation.isSnap()) { + rotation = null; + } + } + } + + @EventHandler + public void onPlayerUpdate( PlayerUpdateEvent event) + { + if (event.getStage() == StageEvent.EventStage.POST) + { + lastServerYaw = ((IClientPlayerEntity) mc.player).genyo_addon$getLastSpoofedYaw(); + lastServerPitch = ((IClientPlayerEntity) mc.player).genyo_addon$getLastSpoofedPitch(); + } + } + + /*@EventHandler + public void onKeyboardTick(KeyboardTickEvent event) + { + if (rotation != null && mc.player != null + && RotationsModule.getInstance().getMovementFix()) + { + float forward = mc.player.input.movementForward; + float sideways = mc.player.input.movementSideways; + float delta = (mc.player.getYaw() - rotation.getYaw()) * MathHelper.RADIANS_PER_DEGREE; + float cos = MathHelper.cos(delta); + float sin = MathHelper.sin(delta); + mc.player.input.movementSideways = Math.round(sideways * cos - forward * sin); + mc.player.input.movementForward = Math.round(forward * cos + sideways * sin); + } + } + + @EventHandler + public void onUpdateVelocity(UpdateVelocityEvent event) + { + if (rotation != null && RotationsModule.getInstance().getMovementFix()) + { + event.cancel(); + event.setVelocity(movementInputToVelocity(rotation.getYaw(), event.getMovementInput(), event.getSpeed())); + } + } + + @EventListener + public void onPlayerJump(PlayerJumpEvent event) + { + if (rotation != null && RotationsModule.getInstance().getMovementFix()) + { + if (event.getStage() == StageEvent.EventStage.PRE) + { + prevJumpYaw = mc.player.getYaw(); + mc.player.setYaw(rotation.getYaw()); + if (AnticheatModule.getInstance().getWebJumpFix() && webJumpFix) + { + preJumpFix = mc.player.isSprinting(); + mc.player.setSprinting(false); + } + } + else + { + mc.player.setYaw(prevJumpYaw); + if (webJumpFix) + { + mc.player.setSprinting(preJumpFix); + } + } + } + } + + @EventHandler + public void onRenderPlayer(RenderPlayerEvent event) + { + if (event.getEntity() == mc.player && rotation != null) + { + // Match packet server rotations + event.setYaw(Interpolation.interpolateFloat(prevYaw, getServerYaw(), mc.getRenderTickCounter().getTickDelta(true))); + event.setPitch(Interpolation.interpolateFloat(prevPitch, getServerPitch(), mc.getRenderTickCounter().getTickDelta(true))); + prevYaw = event.getYaw(); + prevPitch = event.getPitch(); + event.cancel(); + } + }*/ + + /** + * @param rotation + */ + public void setRotation(Rotation rotation) + { + + /*if (RotationsModule.getInstance().getMouseSensFix()) + { + double fix = Math.pow(mc.options.getMouseSensitivity().getValue() * 0.6 + 0.2, 3.0) * 1.2; + rotation.setYaw((float) (rotation.getYaw() - (rotation.getYaw() - serverYaw) % fix)); + rotation.setPitch((float) (rotation.getPitch() - (rotation.getPitch() - serverPitch) % fix)); + }*/ + if (rotation.getPriority() == MAX_VALUE) + { + this.rotation = rotation; + } + + Rotation request = requests.stream().filter(r -> rotation.getPriority() == r.getPriority()).findFirst().orElse(null); + if (request == null) + { + requests.add(rotation); + } + else + { + // r.setPriority(); + request.setYaw(rotation.getYaw()); + request.setPitch(rotation.getPitch()); + } + } + + /** + * @param yaw + * @param pitch + */ + public void setRotationClient(float yaw, float pitch) + { + if (mc.player == null) + { + return; + } + mc.player.setYaw(yaw); + mc.player.setPitch(MathHelper.clamp(pitch, -90.0f, 90.0f)); + } + + public void setRotationSilent(float yaw, float pitch) + { + setRotation(new Rotation(MAX_VALUE, yaw, pitch, true)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + mc.player.getX(), mc.player.getY(), mc.player.getZ(), yaw, pitch, mc.player.isOnGround(), mc.player.horizontalCollision)); + } + + // This is only required by grim because of rotation movement checks + public void setRotationSilentSync() + { + float yaw = mc.player.getYaw(); + float pitch = mc.player.getPitch(); + setRotation(new Rotation(MAX_VALUE, yaw, pitch, true)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + mc.player.getX(), mc.player.getY(), mc.player.getZ(), yaw, pitch, mc.player.isOnGround(), mc.player.horizontalCollision)); + // Managers.NETWORK.sendSequencedPacket((s) -> new PlayerInteractItemC2SPacket(Hand.MAIN_HAND, s)); + } + + /** + * @param request + */ + public boolean removeRotation(Rotation request) + { + return requests.remove(request); + } + + public boolean isRotationBlocked(int priority) + { + return rotation != null && priority < rotation.getPriority(); + } + + /*public boolean isDoneRotating() + { + return rotateTicks > RotationsModule.getInstance().getPreserveTicks(); + }*/ + + public boolean isRotating() + { + return rotation != null; + } + + public float getRotationYaw() + { + return rotation.getYaw(); + } + + public float getRotationPitch() + { + return rotation.getPitch(); + } + + /** + * @return + */ + public float getServerYaw() + { + return serverYaw; + } + + /** + * @return + */ + public float getWrappedYaw() + { + return MathHelper.wrapDegrees(serverYaw); + } + + /** + * @return + */ + public float getServerPitch() + { + return serverPitch; + } + + // + private Vec3d movementInputToVelocity(float yaw, Vec3d movementInput, float speed) + { + double d = movementInput.lengthSquared(); + if (d < 1.0E-7) + { + return Vec3d.ZERO; + } + Vec3d vec3d = (d > 1.0 ? movementInput.normalize() : movementInput).multiply(speed); + float f = MathHelper.sin(yaw * MathHelper.RADIANS_PER_DEGREE); + float g = MathHelper.cos(yaw * MathHelper.RADIANS_PER_DEGREE); + return new Vec3d(vec3d.x * (double) g - vec3d.z * (double) f, vec3d.y, vec3d.z * (double) g + vec3d.x * (double) f); + } + + private Rotation getRotationRequest() + { + Rotation rotationRequest = null; + int priority = 0; + for (Rotation request : requests) + { + if (request.getPriority() > priority) + { + rotationRequest = request; + priority = request.getPriority(); + } + } + return rotationRequest; + } + +} diff --git a/src/main/java/com/genyo/addon/managers/world/BlockManager.java b/src/main/java/com/genyo/addon/managers/world/BlockManager.java new file mode 100644 index 0000000..3a2e6de --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/world/BlockManager.java @@ -0,0 +1,122 @@ +package com.genyo.addon.managers.world; + +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; +import net.minecraft.util.math.BlockPos; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class BlockManager { + + private final List breakPositions = new CopyOnWriteArrayList<>(); + + @EventHandler + public void onTick(TickEvent.Pre event) + { + if (mc.player == null || mc.world == null) { + breakPositions.clear(); + return; + } + + for (BreakEntry blockEntry : breakPositions) + { + blockEntry.updateDamage(); + } + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) + { + if (mc.player == null || mc.world == null) return; + + if (event.packet instanceof BlockBreakingProgressS2CPacket packet) { + if (countBreaks(packet.getEntityId()) >= 2) { + breakPositions.stream().filter(d -> d.getEntityId() == packet.getEntityId()) + .min(Comparator.comparingLong(BreakEntry::getStartTime)).ifPresent(breakPositions::remove); + } + BreakEntry data = new BreakEntry(packet.getEntityId(), packet.getPos()); + data.startMining(); + breakPositions.add(data); + } + } + + public long countBreaks(int entityId) + { + return breakPositions.stream().filter(d -> d.getEntityId() == entityId).count(); + } + + public boolean isInstantMine(BlockPos pos) + { + return breakPositions.getFirst().getPos().equals(pos); + } + + public boolean isBreaking(BlockPos pos) + { + return breakPositions.stream().anyMatch(d -> d.getPos().equals(pos)); + } + + public boolean isPassed(BlockPos pos, float blockDamage) + { + return breakPositions.stream().anyMatch(d -> d.getPos().equals(pos) && d.getBlockDamage() >= blockDamage); + } + + public Set getMines(float blockDamage) + { + return breakPositions.stream().filter(d -> isPassed(d.getPos(), blockDamage)).map(BreakEntry::getPos).collect(Collectors.toSet()); + } + + public static class BreakEntry + { + private final int entityId; + private final BlockPos pos; + private long startTime; + private float blockDamage; + private boolean started; + + public BreakEntry(int entityId, BlockPos pos) + { + this.entityId = entityId; + this.pos = pos; + } + + public void updateDamage() + { + if (started) blockDamage += mc.world.getBlockState(pos).calcBlockBreakingDelta(mc.player, mc.world, pos); + } + + public void startMining() + { + started = true; + startTime = System.currentTimeMillis(); + } + + public BlockPos getPos() + { + return pos; + } + + public float getBlockDamage() + { + return Math.min(blockDamage, 1.0f); + } + + public int getEntityId() + { + return entityId; + } + + public long getStartTime() + { + return startTime; + } + } + +} diff --git a/src/main/java/com/genyo/addon/managers/world/tick/TickManager.java b/src/main/java/com/genyo/addon/managers/world/tick/TickManager.java new file mode 100644 index 0000000..0912fe4 --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/world/tick/TickManager.java @@ -0,0 +1,173 @@ +package com.genyo.addon.managers.world.tick; + +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.events.render.TickCounterEvent; +import com.genyo.addon.utils.collection.EvictingQueue; +import com.google.common.collect.Lists; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.NoSuchElementException; +import java.util.Queue; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class TickManager { + + private final Deque ticks = new EvictingQueue<>(20); + // The TPS tick handler. + // + private long time; + // + private float clientTick = 1.0f; + + @EventHandler + public void onDisconnect(DisconnectEvent event) + { + ticks.clear(); + } + + /** + * @param event + * @see WorldTimeUpdateS2CPacket + */ + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) + { + if (mc.player == null || mc.world == null) + { + return; + } + // ticks/actual + if (event.packet instanceof WorldTimeUpdateS2CPacket) + { + float last = 20000.0f / (System.currentTimeMillis() - time); + ticks.addFirst(last); + time = System.currentTimeMillis(); + } + } + + /** + * @param ticks + */ + public void setClientTick(float ticks) + { + clientTick = ticks; + } + + /** + * @param event + */ + @EventHandler + public void onTickCounter(TickCounterEvent event) + { + if (clientTick != 1.0f) + { + event.cancel(); + event.ticks = clientTick; + } + } + + /** + * @return + */ + public Queue getTicks() + { + return ticks; + } + + // So many fucking issues with the EvictingQueue fuck stackoverflow + // Im just gonna try catch everything atp + + /** + * @return + */ + public float getTpsAverage() + { + float avg = 0.0f; + try + { + // fix ConcurrentModificationException + ArrayList ticksCopy = Lists.newArrayList(ticks); + if (!ticksCopy.isEmpty()) + { + for (float t : ticksCopy) + { + avg += t; + } + avg /= Math.max(ticksCopy.size(), 1.0f); + } + } + catch (NullPointerException e) + { + + } + return Math.min(100.0f, avg); // Server may compensate + } + + /** + * @return + */ + public float getTpsCurrent() + { + try + { + if (!ticks.isEmpty()) + { + return Math.min(100.0f, ticks.getFirst()); + } + } + catch (NoSuchElementException ignored) + { + + } + return 20.0f; + } + + /** + * @return + */ + public float getTpsMin() + { + float min = 20.0f; + try + { + for (float t : ticks) + { + if (t < min) + { + min = t; + } + } + } + catch (NullPointerException e) + { + + } + return min; + } + + public boolean isTicksFilled() + { + return ticks.size() >= 20; + } + + /** + * @param tps + * @return + */ + public float getTickSync(TickSync tps) + { + return switch (tps) + { + case AVERAGE -> getTpsAverage(); + case CURRENT -> getTpsCurrent(); + case MINIMAL -> getTpsMin(); + case NONE -> 20.0f; + }; + } + +} diff --git a/src/main/java/com/genyo/addon/managers/world/tick/TickSync.java b/src/main/java/com/genyo/addon/managers/world/tick/TickSync.java new file mode 100644 index 0000000..797840b --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/world/tick/TickSync.java @@ -0,0 +1,8 @@ +package com.genyo.addon.managers.world.tick; + +public enum TickSync { + CURRENT, + AVERAGE, + MINIMAL, + NONE +} diff --git a/src/main/java/com/genyo/addon/mixin/ClientPlayerInteractionManagerMixin.java b/src/main/java/com/genyo/addon/mixin/ClientPlayerInteractionManagerMixin.java new file mode 100644 index 0000000..c7dc3ce --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/ClientPlayerInteractionManagerMixin.java @@ -0,0 +1,75 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.AttackBlockEvent; +import com.genyo.addon.events.network.ItemDesyncEvent; +import com.genyo.addon.events.network.PacketSneakingEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.block.BlockState; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@Mixin(ClientPlayerInteractionManager.class) +public class ClientPlayerInteractionManagerMixin { + + /** + * @param pos + * @param direction + * @param cir + */ + @Inject(method = "attackBlock", at = @At(value = "HEAD"), cancellable = true) + private void hookAttackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { + BlockState state = mc.world.getBlockState(pos); + if (MeteorClient.EVENT_BUS.post(AttackBlockEvent.get(pos, state, direction)).isCancelled()) cir.cancel(); + } + + @Redirect( + method = "interactBlockInternal", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/network/ClientPlayerEntity;getStackInHand(Lnet/minecraft/util/Hand;)Lnet/minecraft/item/ItemStack;")) + private ItemStack hookRedirectInteractBlockInternal$getStackInHand(ClientPlayerEntity entity, Hand hand) + { + if (hand.equals(Hand.OFF_HAND)) + { + return entity.getStackInHand(hand); + } + ItemDesyncEvent itemDesyncEvent = new ItemDesyncEvent(); + MeteorClient.EVENT_BUS.post(itemDesyncEvent); + + return itemDesyncEvent.isCancelled() ? itemDesyncEvent.stack : entity.getStackInHand(Hand.MAIN_HAND); + } + + @Redirect( + method = "interactBlockInternal", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;isEmpty()Z", + ordinal = 0)) + private boolean hookRedirectInteractBlockInternal$getMainHandStack(ItemStack instance) + { + ItemDesyncEvent itemDesyncEvent = new ItemDesyncEvent(); + MeteorClient.EVENT_BUS.post(itemDesyncEvent); + + return itemDesyncEvent.isCancelled() ? itemDesyncEvent.stack.isEmpty() : instance.isEmpty(); + } + + @Redirect(method = "interactBlockInternal", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;shouldCancelInteraction()Z")) + private boolean hookRedirectInteractBlockInternal$shouldCancelInteraction(ClientPlayerEntity player) + { + PacketSneakingEvent packetSneakingEvent = new PacketSneakingEvent(); + MeteorClient.EVENT_BUS.post(packetSneakingEvent); + return player.isSneaking() || packetSneakingEvent.isCancelled(); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/DefaultSettingsWidgetFactoryMixin.java b/src/main/java/com/genyo/addon/mixin/DefaultSettingsWidgetFactoryMixin.java index 1bf5507..82dff8f 100644 --- a/src/main/java/com/genyo/addon/mixin/DefaultSettingsWidgetFactoryMixin.java +++ b/src/main/java/com/genyo/addon/mixin/DefaultSettingsWidgetFactoryMixin.java @@ -1,11 +1,13 @@ package com.genyo.addon.mixin; +import com.genyo.addon.settings.FloatSetting; import com.genyo.addon.settings.playerlist.ListGroupSetting; import meteordevelopment.meteorclient.gui.DefaultSettingsWidgetFactory; import meteordevelopment.meteorclient.gui.GuiTheme; import meteordevelopment.meteorclient.gui.utils.SettingsWidgetFactory; import meteordevelopment.meteorclient.gui.widgets.containers.WContainer; import meteordevelopment.meteorclient.gui.widgets.containers.WTable; +import meteordevelopment.meteorclient.gui.widgets.input.WDoubleEdit; import meteordevelopment.meteorclient.settings.Setting; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,6 +22,9 @@ public abstract class DefaultSettingsWidgetFactoryMixin extends SettingsWidgetFa @Shadow private void selectW(WContainer c, Setting setting, Runnable action) {} + @Shadow + private void reset(WContainer c, Setting setting, Runnable action) {} + public DefaultSettingsWidgetFactoryMixin(GuiTheme theme) { super(theme); } @@ -27,6 +32,7 @@ public DefaultSettingsWidgetFactoryMixin(GuiTheme theme) { @Inject(method = "", at = @At("TAIL")) protected void genyo(CallbackInfo info) { factories.put(ListGroupSetting.class, (table, setting) -> listGroupW(table, (ListGroupSetting) setting)); + factories.put(FloatSetting.class, (table, setting) -> floatW(table, (FloatSetting) setting)); } @Unique @@ -34,4 +40,19 @@ private void listGroupW(WTable table, ListGroupSetting setting) { WTable wtable = table.add(theme.table()).expandX().widget(); ListGroupSetting.fillTable(theme, wtable, setting); } + + @Unique + private void floatW(WTable table, FloatSetting setting) { + WDoubleEdit edit = theme.doubleEdit(setting.get(), setting.min, setting.max, setting.sliderMin, setting.sliderMax, setting.decimalPlaces, setting.noSlider); + table.add(edit).expandX(); + + Runnable action = () -> { + if (!setting.set((float) edit.get())) edit.set(setting.get()); + }; + + if (setting.onSliderRelease) edit.actionOnRelease = action; + else edit.action = action; + + reset(table, setting, () -> edit.set(setting.get())); + } } diff --git a/src/main/java/com/genyo/addon/mixin/MixinClientConnection.java b/src/main/java/com/genyo/addon/mixin/MixinClientConnection.java new file mode 100644 index 0000000..ea0f136 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/MixinClientConnection.java @@ -0,0 +1,25 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.network.DisconnectEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.network.ClientConnection; +import net.minecraft.text.Text; +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(ClientConnection.class) +public class MixinClientConnection { + + /** + * @param disconnectReason + * @param ci + */ + @Inject(method = "disconnect*", at = @At(value = "HEAD")) + private void hookDisconnect(Text disconnectReason, CallbackInfo ci) + { + MeteorClient.EVENT_BUS.post(new DisconnectEvent()); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/MixinConnectScreen.java b/src/main/java/com/genyo/addon/mixin/MixinConnectScreen.java new file mode 100644 index 0000000..7b5f8d4 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/MixinConnectScreen.java @@ -0,0 +1,30 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.network.ConnectScreenEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.multiplayer.ConnectScreen; +import net.minecraft.client.network.CookieStorage; +import net.minecraft.client.network.ServerAddress; +import net.minecraft.client.network.ServerInfo; +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(ConnectScreen.class) +public abstract class MixinConnectScreen { + + /** + * @param client + * @param address + * @param info + * @param ci + */ + @Inject(method = "connect(Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/client/network/ServerAddress;Lnet/minecraft/client/network/ServerInfo;Lnet/minecraft/client/network/CookieStorage;)V", at = @At(value = "HEAD")) + private void onConnect(MinecraftClient client, ServerAddress address, ServerInfo info, CookieStorage cookieStorage, CallbackInfo ci) + { + MeteorClient.EVENT_BUS.post(ConnectScreenEvent.get(address, info)); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/MixinItemUsageContext.java b/src/main/java/com/genyo/addon/mixin/MixinItemUsageContext.java new file mode 100644 index 0000000..c9d2d59 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/MixinItemUsageContext.java @@ -0,0 +1,27 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.network.ItemDesyncEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +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.CallbackInfoReturnable; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@Mixin(ItemUsageContext.class) +public final class MixinItemUsageContext { + + @Inject(method = "getStack", at = @At("RETURN"), cancellable = true) + public void hookGetStack(CallbackInfoReturnable cir) { + ItemDesyncEvent itemDesyncEvent = new ItemDesyncEvent(); + MeteorClient.EVENT_BUS.post(itemDesyncEvent); + + if (mc.player != null && cir.getReturnValue().equals(mc.player.getMainHandStack()) && itemDesyncEvent.isCancelled()) + { + cir.setReturnValue(itemDesyncEvent.stack); + } + } +} diff --git a/src/main/java/com/genyo/addon/mixin/MixinKeyboardInput.java b/src/main/java/com/genyo/addon/mixin/MixinKeyboardInput.java new file mode 100644 index 0000000..c212ea2 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/MixinKeyboardInput.java @@ -0,0 +1,40 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.keyboard.KeyboardTickEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.input.Input; +import net.minecraft.client.input.KeyboardInput; +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(KeyboardInput.class) +public class MixinKeyboardInput { + + @Inject(method = "tick", at = @At("HEAD"), cancellable = true) + protected void hookTick$Pre(CallbackInfo ci) + { + KeyboardTickEvent event = KeyboardTickEvent.Pre.get((Input) (Object) this); + MeteorClient.EVENT_BUS.post(event); + if (event.isCancelled()) + { + ci.cancel(); + } + } + + /** + * @param ci + */ + @Inject(method = "tick", at = @At(value = "TAIL"), cancellable = true) + protected void hookTick$Post(CallbackInfo ci) + { + KeyboardTickEvent event = KeyboardTickEvent.Post.get((Input) (Object) this); + MeteorClient.EVENT_BUS.post(event); + if (event.isCancelled()) + { + ci.cancel(); + } + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/MixinMinecraftClient.java b/src/main/java/com/genyo/addon/mixin/MixinMinecraftClient.java new file mode 100644 index 0000000..eb8e92b --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/MixinMinecraftClient.java @@ -0,0 +1,25 @@ +package com.genyo.addon.mixin; + +import com.genyo.addon.events.RunTickEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.MinecraftClient; +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(MinecraftClient.class) +public abstract class MixinMinecraftClient { + + /** + * @param ci + */ + @Inject(method = "run", at = @At(value = "INVOKE", target = + "Lnet/minecraft/client/MinecraftClient;render(Z)V", shift = At.Shift.BEFORE)) + private void hookRun(CallbackInfo ci) + { + final RunTickEvent runTickEvent = new RunTickEvent(); + MeteorClient.EVENT_BUS.post(runTickEvent); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/accessor/AccessorBundlePacket.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorBundlePacket.java new file mode 100644 index 0000000..36cdf1d --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorBundlePacket.java @@ -0,0 +1,16 @@ +package com.genyo.addon.mixin.accessor; + +import net.minecraft.network.packet.BundlePacket; +import net.minecraft.network.packet.Packet; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(BundlePacket.class) +public interface AccessorBundlePacket { + + @Accessor("packets") + @Mutable + void setIterable(Iterable> iterable); + +} diff --git a/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientConnection.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientConnection.java new file mode 100644 index 0000000..7a36802 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientConnection.java @@ -0,0 +1,16 @@ +package com.genyo.addon.mixin.accessor; + +import net.minecraft.network.ClientConnection; +import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.Packet; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import javax.annotation.Nullable; + +@Mixin(ClientConnection.class) +public interface AccessorClientConnection { + + @Invoker("sendInternal") + void hookSendInternal(Packet packet, @Nullable PacketCallbacks callbacks, boolean flush); +} diff --git a/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientPlayerInteractionManager.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientPlayerInteractionManager.java new file mode 100644 index 0000000..3a91b7f --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientPlayerInteractionManager.java @@ -0,0 +1,35 @@ +package com.genyo.addon.mixin.accessor; + +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ClientPlayerInteractionManager.class) +public interface AccessorClientPlayerInteractionManager { + + /** + * + */ + @Invoker("syncSelectedSlot") + void hookSyncSelectedSlot(); + + @Invoker("interactBlockInternal") + ActionResult hookInteractBlockInternal(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult); + + /** + * @return + */ + @Accessor("currentBreakingProgress") + float hookGetCurrentBreakingProgress(); + + /** + * @param currentBreakingProgress + */ + @Accessor("currentBreakingProgress") + void hookSetCurrentBreakingProgress(float currentBreakingProgress); +} diff --git a/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientWorld.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientWorld.java new file mode 100644 index 0000000..b089191 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorClientWorld.java @@ -0,0 +1,35 @@ +package com.genyo.addon.mixin.accessor; + +import net.minecraft.client.network.PendingUpdateManager; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ClientWorld.class) +public interface AccessorClientWorld { + + /** + * @param x + * @param y + * @param z + * @param event + * @param category + * @param volume + * @param pitch + * @param useDistance + * @param seed + */ + @Invoker("playSound") + void hookPlaySound(double x, double y, double z, SoundEvent event, + SoundCategory category, float volume, float pitch, + boolean useDistance, long seed); + + /** + * @return + */ + @Invoker("getPendingUpdateManager") + PendingUpdateManager hookGetPendingUpdateManager(); + +} diff --git a/src/main/java/com/genyo/addon/mixin/accessor/AccessorEntityVelocityUpdateS2CPacket.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorEntityVelocityUpdateS2CPacket.java new file mode 100644 index 0000000..16b6c71 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorEntityVelocityUpdateS2CPacket.java @@ -0,0 +1,22 @@ +package com.genyo.addon.mixin.accessor; + +import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EntityVelocityUpdateS2CPacket.class) +public interface AccessorEntityVelocityUpdateS2CPacket { + + @Accessor("velocityX") + @Mutable + void setVelocityX(int velocityX); + + @Accessor("velocityY") + @Mutable + void setVelocityY(int velocityY); + + @Accessor("velocityZ") + @Mutable + void setVelocityZ(int velocityZ); +} diff --git a/src/main/java/com/genyo/addon/mixin/AccessorGameOptions.java b/src/main/java/com/genyo/addon/mixin/accessor/AccessorGameOptions.java similarity index 92% rename from src/main/java/com/genyo/addon/mixin/AccessorGameOptions.java rename to src/main/java/com/genyo/addon/mixin/accessor/AccessorGameOptions.java index ce299d9..67eed56 100644 --- a/src/main/java/com/genyo/addon/mixin/AccessorGameOptions.java +++ b/src/main/java/com/genyo/addon/mixin/accessor/AccessorGameOptions.java @@ -1,4 +1,4 @@ -package com.genyo.addon.mixin; +package com.genyo.addon.mixin.accessor; import net.minecraft.client.option.GameOptions; import net.minecraft.entity.player.PlayerModelPart; diff --git a/src/main/java/com/genyo/addon/mixin/IEntity.java b/src/main/java/com/genyo/addon/mixin/entity/IEntity.java similarity index 92% rename from src/main/java/com/genyo/addon/mixin/IEntity.java rename to src/main/java/com/genyo/addon/mixin/entity/IEntity.java index 668cc6f..6786b38 100644 --- a/src/main/java/com/genyo/addon/mixin/IEntity.java +++ b/src/main/java/com/genyo/addon/mixin/entity/IEntity.java @@ -1,4 +1,4 @@ -package com.genyo.addon.mixin; +package com.genyo.addon.mixin.entity; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/com/genyo/addon/mixin/entity/MixinEntity.java b/src/main/java/com/genyo/addon/mixin/entity/MixinEntity.java new file mode 100644 index 0000000..3a59fe3 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/entity/MixinEntity.java @@ -0,0 +1,26 @@ +package com.genyo.addon.mixin.entity; + +import com.genyo.addon.events.entity.player.PushEntityEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.entity.Entity; +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(Entity.class) +public class MixinEntity { + + /** + * @param entity + * @param ci + */ + @Inject(method = "pushAwayFrom", at = @At(value = "HEAD"), cancellable = true) + private void hookPushAwayFrom(Entity entity, CallbackInfo ci) + { + PushEntityEvent pushEntityEvent = PushEntityEvent.get((Entity) (Object) this, entity); + MeteorClient.EVENT_BUS.post(pushEntityEvent); + + if (pushEntityEvent.isCancelled()) ci.cancel(); + } +} diff --git a/src/main/java/com/genyo/addon/mixin/entity/player/MixinPlayerEntity.java b/src/main/java/com/genyo/addon/mixin/entity/player/MixinPlayerEntity.java new file mode 100644 index 0000000..96d989e --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/entity/player/MixinPlayerEntity.java @@ -0,0 +1,36 @@ +package com.genyo.addon.mixin.entity.player; + +import com.genyo.addon.events.entity.player.PushFluidsEvent; +import meteordevelopment.meteorclient.MeteorClient; +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.CallbackInfoReturnable; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@Mixin(PlayerEntity.class) +public class MixinPlayerEntity { + + /** + * @param cir + */ + @Inject(method = "isPushedByFluids", at = @At(value = "HEAD"), + cancellable = true) + private void hookIsPushedByFluids(CallbackInfoReturnable cir) + { + if ((Object) this != mc.player) + { + return; + } + + PushFluidsEvent pushFluidsEvent = new PushFluidsEvent(); + MeteorClient.EVENT_BUS.post(pushFluidsEvent); + if (pushFluidsEvent.isCancelled()) { + cir.setReturnValue(false); + cir.cancel(); + } + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/meteor/MixinSetting.java b/src/main/java/com/genyo/addon/mixin/meteor/MixinSetting.java new file mode 100644 index 0000000..81babc5 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/meteor/MixinSetting.java @@ -0,0 +1,19 @@ +package com.genyo.addon.mixin.meteor; + +import com.genyo.addon.events.meteor.SettingChangedEvent; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.settings.Setting; +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(Setting.class) +public class MixinSetting { + + /*@Inject(method = "onChanged()V", at = @At("TAIL")) + protected void injectOnChanged(CallbackInfo ci) { + MeteorClient.EVENT_BUS.post(SettingChangedEvent.get((Setting) (Object) this)); + }*/ + +} diff --git a/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayNetworkHandler.java b/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayNetworkHandler.java new file mode 100644 index 0000000..263b6bf --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayNetworkHandler.java @@ -0,0 +1,44 @@ +package com.genyo.addon.mixin.network; + +import com.genyo.addon.mixin.accessor.AccessorClientConnection; +import com.genyo.addon.imixins.IClientPlayNetworkHandler; +import com.genyo.addon.modules.movement.GenyoVelocity; +import meteordevelopment.meteorclient.mixininterface.IExplosionS2CPacket; +import meteordevelopment.meteorclient.systems.modules.Modules; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPlayNetworkHandler.class) +public class MixinClientPlayNetworkHandler implements IClientPlayNetworkHandler { + + @Shadow + public ClientConnection getConnection() { + return null; + } + + @Inject(method = "onExplosion", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER)) + private void onExplosionVelocity(ExplosionS2CPacket packet, CallbackInfo ci) { + GenyoVelocity velocity = Modules.get().get(GenyoVelocity.class); + if (velocity.explosionConfig.get()) { + IExplosionS2CPacket explosionPacket = (IExplosionS2CPacket) (Object) packet; + explosionPacket.meteor$setVelocityX((float) (packet.playerKnockback().orElse(Vec3d.ZERO).x * velocity.getHorizontal(velocity.explosionsHorizontal))); + explosionPacket.meteor$setVelocityY((float) (packet.playerKnockback().orElse(Vec3d.ZERO).y * velocity.getVertical(velocity.explosionsVertical))); + explosionPacket.meteor$setVelocityZ((float) (packet.playerKnockback().orElse(Vec3d.ZERO).z * velocity.getHorizontal(velocity.explosionsHorizontal))); + } + } + + @Override + public void sendQuietPacket(Packet packet) + { + ((AccessorClientConnection) getConnection()).hookSendInternal(packet, null, true); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayerEntity.java b/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayerEntity.java new file mode 100644 index 0000000..a23b383 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/network/MixinClientPlayerEntity.java @@ -0,0 +1,133 @@ +package com.genyo.addon.mixin.network; + +import com.genyo.addon.events.StageEvent; +import com.genyo.addon.events.sync.SyncEvent; +import com.genyo.addon.events.network.*; +import com.genyo.addon.imixins.IClientPlayerEntity; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.util.Hand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static com.genyo.addon.modules.GenyoModule.fullNullCheck; +import static meteordevelopment.meteorclient.MeteorClient.mc; + +@Mixin(ClientPlayerEntity.class) +public abstract class MixinClientPlayerEntity implements IClientPlayerEntity { + + @Unique + boolean pre_sprint_state = false; + @Unique + private boolean updateLock = false; + @Unique + private Runnable postAction; + + @Shadow + private float lastYaw; + @Shadow + private float lastPitch; + + @Shadow + protected abstract void sendMovementPackets(); + + @Shadow + public abstract float getYaw(float tickDelta); + + @Shadow + public abstract float getPitch(float tickDelta); + + /** + * @param ci + */ + @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/" + + "minecraft/client/network/AbstractClientPlayerEntity;tick()V", + shift = At.Shift.BEFORE, ordinal = 0)) + private void hookTickPre(CallbackInfo ci) + { + MeteorClient.EVENT_BUS.post(new PlayerTickEvent()); + } + + /** + * @param ci + */ + @Inject(method = "sendMovementPackets", at = @At(value = "HEAD"), cancellable = true) + private void hookSendMovementPackets(CallbackInfo ci) { + //if (fullNullCheck()) return; + SyncEvent.Pre event = SyncEvent.Pre.get(getYaw(mc.getRenderTickCounter().getTickDelta(true)), getPitch(mc.getRenderTickCounter().getTickDelta(true))); + MeteorClient.EVENT_BUS.post(event); + postAction = event.postAction; + + PlayerUpdateEvent playerUpdateEvent = new PlayerUpdateEvent(); + playerUpdateEvent.setStage(StageEvent.EventStage.PRE); + MeteorClient.EVENT_BUS.post(playerUpdateEvent); + + MovementPacketsEvent movementPacketsEvent = MovementPacketsEvent.get(mc.player.getX(), mc.player.getY(), + mc.player.getZ(), mc.player.getYaw(), mc.player.getPitch(), mc.player.isOnGround()); + MeteorClient.EVENT_BUS.post(movementPacketsEvent); + + playerUpdateEvent.setStage(StageEvent.EventStage.POST); + } + + @Inject(method = "sendMovementPackets", at = @At("RETURN"), cancellable = true) + private void sendMovementPacketsPostHook(CallbackInfo info) { + //if (fullNullCheck()) return; + //mc.player.lastSprinting = pre_sprint_state; + + SyncEvent.Post event = SyncEvent.Post.get(); + MeteorClient.EVENT_BUS.post(event); + + if(postAction != null) { + postAction.run(); + postAction = null; + } + + if (event.isCancelled()) + info.cancel(); + } + + /** + * @param hand + * @param ci + */ + @Inject(method = "setCurrentHand", at = @At(value = "HEAD")) + private void hookSetCurrentHand(Hand hand, CallbackInfo ci) + { + MeteorClient.EVENT_BUS.post(SetCurrentHandEvent.get(hand)); + } + + /** + * @param x + * @param z + * @param ci + */ + @Inject(method = "pushOutOfBlocks", at = @At(value = "HEAD"), + cancellable = true) + private void onPushOutOfBlocks(double x, double z, CallbackInfo ci) + { + /*PushOutOfBlocksEvent pushOutOfBlocksEvent = new PushOutOfBlocksEvent(); + MeteorClient.EVENT_BUS.post(pushOutOfBlocksEvent); + + if (pushOutOfBlocksEvent.isCancelled()) { + ci.cancel(); + }*/ + } + + @Override + public float genyo_addon$getLastSpoofedYaw() + { + return lastYaw; + } + + @Override + public float genyo_addon$getLastSpoofedPitch() + { + return lastPitch; + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/network/MixinServerPlayerEntity.java b/src/main/java/com/genyo/addon/mixin/network/MixinServerPlayerEntity.java new file mode 100644 index 0000000..9f5ba41 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/network/MixinServerPlayerEntity.java @@ -0,0 +1,20 @@ +package com.genyo.addon.mixin.network; + +import com.genyo.addon.events.world.LoadWorldEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +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(ServerPlayerEntity.class) +public class MixinServerPlayerEntity { + + @Inject(method = "worldChanged", at = @At(value = "HEAD")) + private void hookMoveToWorld(ServerWorld origin, CallbackInfo ci) + { + MeteorClient.EVENT_BUS.post(new LoadWorldEvent()); + } +} diff --git a/src/main/java/com/genyo/addon/mixin/render/MixinRenderTickCounter.java b/src/main/java/com/genyo/addon/mixin/render/MixinRenderTickCounter.java new file mode 100644 index 0000000..2bebdfd --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/render/MixinRenderTickCounter.java @@ -0,0 +1,49 @@ +package com.genyo.addon.mixin.render; + +import com.genyo.addon.events.render.TickCounterEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.render.RenderTickCounter; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(RenderTickCounter.Dynamic.class) +public abstract class MixinRenderTickCounter { + + @Shadow + private float lastFrameDuration; + + @Shadow + private float tickDelta; + + @Shadow + private long prevTimeMillis; + + @Final + @Shadow + private float tickTime; + + /** + * @param timeMillis + * @param cir + */ + @Inject(method = "beginRenderTick(J)I", at = @At(value = "HEAD"), cancellable = true) + private void hookBeginRenderTick(long timeMillis, CallbackInfoReturnable cir) + { + TickCounterEvent tickCounterEvent = new TickCounterEvent(); + MeteorClient.EVENT_BUS.post(tickCounterEvent); + if (tickCounterEvent.isCancelled()) + { + lastFrameDuration = ((timeMillis - prevTimeMillis) / tickTime) * tickCounterEvent.ticks; + prevTimeMillis = timeMillis; + tickDelta += lastFrameDuration; + int i = (int) tickDelta; + tickDelta -= i; + cir.setReturnValue(i); + } + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/render/MixinWorldRenderer.java b/src/main/java/com/genyo/addon/mixin/render/MixinWorldRenderer.java new file mode 100644 index 0000000..6f4e9fe --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/render/MixinWorldRenderer.java @@ -0,0 +1,31 @@ +package com.genyo.addon.mixin.render; + +import com.genyo.addon.events.render.RenderWorldEvent; +import com.mojang.blaze3d.systems.RenderSystem; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.render.*; +import net.minecraft.client.util.ObjectAllocator; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.RotationAxis; +import org.joml.Matrix4f; +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 MixinWorldRenderer { + + @Inject(method = "render", at = @At(value = "RETURN")) + private void hookRender(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) + { + MatrixStack matrixStack = new MatrixStack(); + RenderSystem.getModelViewStack().pushMatrix().mul(matrixStack.peek().getPositionMatrix()); + matrixStack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); + matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0f)); + final RenderWorldEvent renderWorldEvent = RenderWorldEvent.get(matrixStack, tickCounter.getTickDelta(true)); + MeteorClient.EVENT_BUS.post(renderWorldEvent); + RenderSystem.getModelViewStack().popMatrix(); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/world/MixinClientWorld.java b/src/main/java/com/genyo/addon/mixin/world/MixinClientWorld.java new file mode 100644 index 0000000..9e98998 --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/world/MixinClientWorld.java @@ -0,0 +1,34 @@ +package com.genyo.addon.mixin.world; + +import com.genyo.addon.events.world.RemoveEntityEvent; +import meteordevelopment.meteorclient.MeteorClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.world.entity.EntityLookup; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientWorld.class) +public abstract class MixinClientWorld { + + @Shadow + protected abstract EntityLookup getEntityLookup(); + + /** + * @param entityId + * @param removalReason + * @param ci + */ + @Inject(method = "removeEntity", at = @At(value = "HEAD")) + private void hookRemoveEntity(int entityId, Entity.RemovalReason removalReason, CallbackInfo ci) { + Entity entity = getEntityLookup().get(entityId); + if (entity == null) return; + + RemoveEntityEvent removeEntityEvent = RemoveEntityEvent.get(entity, removalReason); + MeteorClient.EVENT_BUS.post(removeEntityEvent); + } + +} diff --git a/src/main/java/com/genyo/addon/modules/GenyoModule.java b/src/main/java/com/genyo/addon/modules/GenyoModule.java index a41f15f..dad9fee 100644 --- a/src/main/java/com/genyo/addon/modules/GenyoModule.java +++ b/src/main/java/com/genyo/addon/modules/GenyoModule.java @@ -1,41 +1,45 @@ package com.genyo.addon.modules; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.managers.player.rotation.Rotation; import meteordevelopment.meteorclient.mixininterface.IChatHud; import meteordevelopment.meteorclient.settings.BoolSetting; import meteordevelopment.meteorclient.settings.Setting; import meteordevelopment.meteorclient.settings.SettingGroup; import meteordevelopment.meteorclient.systems.config.Config; +import meteordevelopment.meteorclient.systems.friends.Friends; import meteordevelopment.meteorclient.systems.modules.Category; import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.meteorclient.systems.modules.Modules; -import meteordevelopment.meteorclient.systems.modules.player.Rotation; import meteordevelopment.meteorclient.utils.player.ChatUtils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.PendingUpdateManager; import net.minecraft.client.network.SequencedPacketCreator; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket; -import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import java.util.Comparator; import java.util.Objects; - -import static meteordevelopment.meteorclient.MeteorClient.mc; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class GenyoModule extends Module { + protected Random RANDOM = ThreadLocalRandom.current(); + private final String prefix = Formatting.GOLD + "" + Formatting.BOLD + "[Genyo]"; public GenyoModule(Category category, String name, String description) { super(category, name, description); } + public static boolean fullNullCheck() { + return MinecraftClient.getInstance().player == null || MinecraftClient.getInstance().world == null; + } + // Messages public void sendToggledMsg() { if (!Config.get().chatFeedback.get() && !chatFeedback && mc.world == null) return; @@ -57,7 +61,7 @@ public void sendDisableMsg(String text) { if (mc.world == null) return; ChatUtils.forceNextPrefixClass(getClass()); - String msg = prefix + " " + Formatting.WHITE + title + Formatting.RED + " OFF " + Formatting.GRAY + text; + String msg = prefix + " " + Formatting.WHITE + title + Formatting.RED + " OFF " + Formatting.GRAY + "- " + text; sendMessage(Text.of(msg), hashCode()); } @@ -94,6 +98,30 @@ public void sendPacket(Packet packet) { mc.getNetworkHandler().sendPacket(packet); } + protected void sendSequencedPacket(SequencedPacketCreator packetCreator) { + if (mc.getNetworkHandler() == null || mc.world == null) return; + + try (PendingUpdateManager pendingUpdateManager = mc.world.getPendingUpdateManager().incrementSequence();) { + int i = pendingUpdateManager.getSequence(); + mc.getNetworkHandler().sendPacket(packetCreator.predict(i)); + } + } + + protected void setRotation(float yaw, float pitch) + { + Managers.ROTATION.setRotation(new Rotation(100, yaw, pitch)); + } + + protected boolean isRotationBlocked() + { + return Managers.ROTATION.isRotationBlocked(100); + } + + protected void setRotationSilent(float yaw, float pitch) + { + Managers.ROTATION.setRotationSilent(yaw, pitch); + } + public void sendSequenced(SequencedPacketCreator packetCreator) { if (mc.interactionManager == null || mc.world == null || mc.getNetworkHandler() == null) return; @@ -158,4 +186,23 @@ public Setting addPauseEat(SettingGroup group) { .build() ); } + + public PlayerEntity getClosestPlayer(double range) { + return mc.world.getPlayers().stream().filter(e -> !(e instanceof ClientPlayerEntity) && !e.isSpectator()) + .filter(e -> mc.player.squaredDistanceTo(e) <= range * range) + //.filter(e -> !Managers.SOCIAL.isFriend(e.getName().getString())) + .filter(e -> !Friends.get().isFriend(e)) + .min(Comparator.comparingDouble(e -> mc.player.squaredDistanceTo(e))).orElse(null); + } + + public boolean checkMultitask() { + return checkMultitask(false); + } + + public boolean checkMultitask(boolean checkOffhand) { + if (checkOffhand && mc.player.getActiveHand() != Hand.MAIN_HAND) { + return false; + } + return mc.player.isUsingItem(); + } } diff --git a/src/main/java/com/genyo/addon/modules/PlacerModule.java b/src/main/java/com/genyo/addon/modules/PlacerModule.java new file mode 100644 index 0000000..86e4fcf --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/PlacerModule.java @@ -0,0 +1,158 @@ +package com.genyo.addon.modules; + +import com.genyo.addon.managers.Managers; +import com.genyo.addon.managers.player.rotation.Rotation; +import meteordevelopment.meteorclient.settings.BoolSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.systems.modules.Category; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +public class PlacerModule extends GenyoModule { + + private final int rotationPriority; + + protected static final BlockState DEFAULT_OBSIDIAN_STATE = Blocks.OBSIDIAN.getDefaultState(); + // Blocks that can prevent explosion damage + private static final List RESISTANT_BLOCKS = new LinkedList<>() + {{ + add(Blocks.OBSIDIAN); + add(Blocks.CRYING_OBSIDIAN); + add(Blocks.ENDER_CHEST); + }}; + + protected final Setting multitaskConfig = settings.getDefaultGroup().add(new BoolSetting.Builder() + .name("Multitask") + .description("Allows mining while using items") + .defaultValue(false) + .build() + ); + + protected final Setting strictDirectionConfig = settings.getDefaultGroup().add(new BoolSetting.Builder() + .name("Strict Direction") + .description("Places on visible sides only") + .defaultValue(false) + .build() + ); + + public PlacerModule(Category category, String name, String desc) + { + super(category, name, desc); + this.rotationPriority = 100; + } + + public PlacerModule(Category category, String name, String desc, int priority) + { + super(category, name, desc); + this.rotationPriority = priority; + } + + protected void setRotation(float yaw, float pitch) + { + Managers.ROTATION.setRotation(new Rotation(getRotationPriority(), yaw, pitch)); + } + + protected int getRotationPriority() + { + return rotationPriority; + } + + protected void setRotationSilent(float yaw, float pitch) + { + Managers.ROTATION.setRotationSilent(yaw, pitch); + } + + /** + * Sets client look yaw and pitch + * + * @param yaw + * @param pitch + */ + protected void setRotationClient(float yaw, float pitch) + { + Managers.ROTATION.setRotationClient(yaw, pitch); + } + + /** + * @return + */ + protected int getResistantBlockItem() + { + final Set blockSlots = new HashSet<>(); + for (final Block type : RESISTANT_BLOCKS) + { + final int slot = getBlockItemSlot(type); + if (slot != -1) + { + blockSlots.add(new BlockSlot(type, slot)); + } + } + + // Prioritize + BlockSlot slot = blockSlots.stream().filter(b -> b.block() == Blocks.OBSIDIAN).findFirst().orElse(null); + if (slot != null) + { + return slot.slot(); + } + BlockSlot slot1 = blockSlots.stream().filter(b -> b.block() == Blocks.CRYING_OBSIDIAN).findFirst().orElse(null); + if (slot1 != null) + { + return slot1.slot(); + } + BlockSlot slot2 = blockSlots.stream().filter(b -> b.block() == Blocks.ENDER_CHEST).findFirst().orElse(null); + if (slot2 != null) + { + return slot2.slot(); + } + return -1; + } + + public record BlockSlot(Block block, int slot) + { + @Override + public boolean equals(Object obj) + { + return obj instanceof BlockSlot b && b.block() == block; + } + } + + protected int getSlot(final Predicate filter) + { + for (int i = 0; i < 9; ++i) + { + final ItemStack itemStack = mc.player.getInventory().getStack(i); + if (!itemStack.isEmpty() && filter.test(itemStack)) + { + return i; + } + } + return -1; + } + + protected int getBlockItemSlot(final Block block) + { + for (int i = 0; i < 9; i++) + { + final ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.getItem() instanceof BlockItem blockItem + && blockItem.getBlock() == block) + { + return i; + } + } + return -1; + } + + + +} diff --git a/src/main/java/com/genyo/addon/modules/combat/GenyoAutoCrystal.java b/src/main/java/com/genyo/addon/modules/combat/GenyoAutoCrystal.java new file mode 100644 index 0000000..b1f72f3 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/combat/GenyoAutoCrystal.java @@ -0,0 +1,2203 @@ +package com.genyo.addon.modules.combat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.network.PlayerTickEvent; +import com.genyo.addon.events.RunTickEvent; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.modules.world.GenyoAutoMine; +import com.genyo.addon.modules.world.GenyoSurroundV2; +import com.genyo.addon.render.animation.Animation; +import com.genyo.addon.settings.FloatSetting; +import com.genyo.addon.utils.collection.EvictingQueue; +import com.genyo.addon.utils.entity.EntityUtil; +import com.genyo.addon.utils.math.PerSecondCounter; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.genyo.addon.utils.player.InventoryUtil; +import com.genyo.addon.utils.player.PlayerUtil; +import com.genyo.addon.utils.world.BlastResistantBlocks; +import com.genyo.addon.utils.world.ExplosionUtil; +import com.google.common.collect.Lists; +import meteordevelopment.meteorclient.events.entity.EntityAddedEvent; +import meteordevelopment.meteorclient.events.game.GameLeftEvent; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.render.Render2DEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.renderer.text.TextRenderer; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.friends.Friends; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.combat.CrystalAura; +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.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.ShulkerBoxBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.decoration.EndCrystalEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.*; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; +import net.minecraft.network.packet.s2c.play.*; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.*; +import net.minecraft.world.RaycastContext; +import org.joml.Vector3d; + +import java.util.*; +import java.util.concurrent.*; + +public class GenyoAutoCrystal extends GenyoModule { + + public GenyoAutoCrystal() { + super(GenyoAddon.GENYO, "genyo-auto-crystal", "neger cock neger cock neger cock"); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgRotate = settings.createGroup("Rotate"); + private final SettingGroup sgTargets = settings.createGroup("Targets"); + private final SettingGroup sgBreak = settings.createGroup("Break"); + private final SettingGroup sgPlace = settings.createGroup("Place"); + private final SettingGroup sgDamage = settings.createGroup("Damage"); + private final SettingGroup sgRender = settings.createGroup("Render"); + + private final Setting multitask = sgGeneral.add(new BoolSetting.Builder() + .name("Allow Multitask") + .description("Allows actions while using items") + .defaultValue(false) + .build() + ); + + private final Setting whileMining = sgGeneral.add(new BoolSetting.Builder() + .name("While Mining") + .description("Allows attacking while mining blocks") + .defaultValue(false) + .build() + ); + + private final Setting targetRange = sgGeneral.add(new FloatSetting.Builder() + .name("Enemy Range") + .description("Range to search for potential enemies") + .min(1.0f) + .defaultValue(10.f) + .max(13.0f) + .build() + ); + + private final Setting instant = sgGeneral.add(new BoolSetting.Builder() + .name("Instant") + .description("Instantly attacks crystals when they spawn") + .defaultValue(false) + .build() + ); + + private final Setting sequential = sgGeneral.add(new EnumSetting.Builder() + .name("Sequential") + .description("Places a crystal after spawn") + .defaultValue(Sequential.NONE) + .build() + ); + + private final Setting idPredict = sgGeneral.add(new BoolSetting.Builder() + .name("Break Predict") + .description("Attempts to predict crystal entity ids") + .defaultValue(false) + .build() + ); + + private final Setting instantCalc = sgGeneral.add(new BoolSetting.Builder() + .name("Instant Calc") + .description("Calculates a crystal when it spawns and attacks if it meets MINIMUM requirements, this will result in non-ideal crystal attacks") + .defaultValue(false) + //.visible(() -> false) + .build() + ); + + private final Setting instantDamage = sgGeneral.add(new FloatSetting.Builder() + .name("Instant Damage") + .description("Minimum damage to attack crystals instantly") + .min(1.0f) + .defaultValue(6.0f) + .max(10.0f) + //.visible(() -> false) + .build() + ); + + private final Setting instantMax = sgGeneral.add(new BoolSetting.Builder() + .name("Instant Max") + .description("Attacks crystals instantly if they exceed the previous max attack damage (Note: This is still not a perfect check because the next tick could have better damages)") + .defaultValue(true) + .build() + ); + + private final Setting raytraceC = sgGeneral.add(new BoolSetting.Builder() + .name("Raytrace") + .description("Raytrace to crystal position") + .defaultValue(true) + .build() + ); + + private final Setting swing = sgGeneral.add(new BoolSetting.Builder() + .name("Swing") + .description("Swing hand when placing and attacking crystals") + .defaultValue(true) + .build() + ); + + private final Setting rotate = sgRotate.add(new BoolSetting.Builder() + .name("Rotate") + .description("Rotate before placing and breaking") + .defaultValue(false) + .build() + ); + + private final Setting strictRotate = sgRotate.add(new EnumSetting.Builder() + .name("Yaw Step") + .description("Rotates yaw over multiple ticks to prevent certain rotation flags in NCP") + .defaultValue(Rotate.OFF) + .build() + ); + + private final Setting rotateLimit = sgRotate.add(new IntSetting.Builder() + .name("Yaw Step Limit") + .description("Maximum yaw rotation in degrees for one tick") + .min(1) + .defaultValue(180) + .max(180) + .visible(() -> rotate.get() && strictRotate.get() != Rotate.OFF) + .build() + ); + + private final Setting players = sgTargets.add(new BoolSetting.Builder() + .name("Players") + .description("Target players") + .defaultValue(true) + .build() + ); + + private final Setting monsters = sgTargets.add(new BoolSetting.Builder() + .name("Monsters") + .description("Target monsters") + .defaultValue(false) + .build() + ); + + private final Setting neutrals = sgTargets.add(new BoolSetting.Builder() + .name("Neutrals") + .description("Target neutrals") + .defaultValue(false) + .build() + ); + + private final Setting animals = sgTargets.add(new BoolSetting.Builder() + .name("Animals") + .description("Target animals") + .defaultValue(false) + .build() + ); + + private final Setting shulkers = sgTargets.add(new BoolSetting.Builder() + .name("Shulkers") + .description("Target shulker boxes") + .defaultValue(false) + .build() + ); + + //Break + private final Setting breakSpeed = sgBreak.add(new FloatSetting.Builder() + .name("Break Speed") + .description("Speed to break crystals") + .min(0.1f) + .defaultValue(18.0f) + .max(20.0f) + .build() + ); + + private final Setting attackDelay = sgBreak.add(new FloatSetting.Builder() + .name("Attack Delay") + .description("Added delays") + .min(0.0f) + .defaultValue(0.0f) + .max(5.0f) + .build() + ); + + private final Setting attackFactorC = sgBreak.add(new IntSetting.Builder() + .name("Attack Factor") + .description("Factor of attack delay") + .min(0) + .defaultValue(0) + .max(3) + .visible(() -> attackDelay.get() > 0.0) + .build() + ); + + private final Setting attackLimit = sgBreak.add(new FloatSetting.Builder() + .name("Attack Limit") + .description("The number of attacks before considering a crystal unbreakable") + .min(0.5f) + .defaultValue(1.5f) + .max(20.0f) + .build() + ); + + private final Setting breakDelayC = sgBreak.add(new BoolSetting.Builder() + .name("Break Delay") + .description("Uses attack latency to calculate break delays") + .defaultValue(false) + .build() + ); + + private final Setting breakTimeout = sgBreak.add(new FloatSetting.Builder() + .name("Break Timeout") + .description("Time after waiting for the average break time before considering a crystal attack failed") + .min(0.0f) + .defaultValue(3.0f) + .max(10.0f) + .visible(breakDelayC::get) + .build() + ); + + private final Setting minTimeout = sgBreak.add(new FloatSetting.Builder() + .name("Min Timeout") + .description("Minimum time before considering a crystal break/place failed") + .min(0.0f) + .defaultValue(5.0f) + .max(20.0f) + .visible(breakDelayC::get) + .build() + ); + + private final Setting ticksExisted = sgBreak.add(new IntSetting.Builder() + .name("Ticks Existed") + .description("Minimum ticks alive to consider crystals for attack") + .min(0) + .defaultValue(0) + .max(10) + .build() + ); + + private final Setting breakRangeC = sgBreak.add(new FloatSetting.Builder() + .name("Break Range") + .description("Range to break crystals") + .min(0.1f) + .defaultValue(4.0f) + .max(6.0f) + .build() + ); + + private final Setting maxYOffset = sgBreak.add(new FloatSetting.Builder() + .name("Max Y Offset") + .description("Maximum crystal y-offset difference") + .min(1.0f) + .defaultValue(5.0f) + .max(10.f) + .build() + ); + + private final Setting breakWallRangeC = sgBreak.add(new FloatSetting.Builder() + .name("Break Wall Range") + .description("Range to break crystals through walls") + .min(0.1f) + .defaultValue(4.0f) + .max(6.0f) + .build() + ); + + private final Setting antiWeakness = sgBreak.add(new EnumSetting.Builder() + .name("Anti Weakness") + .description("Swap to tools before attacking crystals") + .defaultValue(Swap.OFF) + .build() + ); + + private final Setting swapDelay = sgBreak.add(new FloatSetting.Builder() + .name("Swap Penalty") + .description("Delay for attacking after swapping items which prevents NCP flags") + .min(0.0f) + .defaultValue(0.0f) + .max(10.0f) + .build() + ); + + private final Setting inhibit = sgPlace.add(new BoolSetting.Builder() + .name("Inhibit") + .description("Prevents excessive attacks") + .defaultValue(true) + .build() + ); + + private final Setting place = sgPlace.add(new BoolSetting.Builder() + .name("Place") + .description("Places crystals to damage enemies. Place settings will only function if this setting is enabled.") + .defaultValue(true) + .build() + ); + + private final Setting placeSpeed = sgPlace.add(new FloatSetting.Builder() + .name("Place Speed") + .description("Speed to place crystals") + .min(0.1f) + .defaultValue(18.0f) + .max(20.0f) + .visible(place::get) + .build() + ); + + private final Setting placeRangeC = sgPlace.add(new FloatSetting.Builder() + .name("Place Range") + .description("Range to place crystals") + .min(0.1f) + .defaultValue(4.0f) + .max(6.0f) + .visible(place::get) + .build() + ); + + private final Setting placeWallRangeC = sgPlace.add(new FloatSetting.Builder() + .name("Place Wall Range") + .description("Range to place crystals through walls") + .min(0.1f) + .defaultValue(4.0f) + .max(6.0f) + .visible(place::get) + .build() + ); + + private final Setting placeRangeEye = sgPlace.add(new BoolSetting.Builder() + .name("Place Range Eye") + .description("Calculates place ranges starting from the eye position of the player") + .defaultValue(false) + .visible(place::get) + .build() + ); + + private final Setting placeRangeCenter = sgPlace.add(new BoolSetting.Builder() + .name("Place Range Center") + .description("Calculates place ranges to the center of the block") + .defaultValue(true) + .visible(place::get) + .build() + ); + + private final Setting autoSwap = sgPlace.add(new EnumSetting.Builder() + .name("Swap") + .description("Swaps to an end crystal before placing if the player is not holding one") + .defaultValue(Swap.OFF) + .visible(place::get) + .build() + ); + + private final Setting antiSurroundC = sgPlace.add(new BoolSetting.Builder() + .name("Anti Surround") + .description("Places on mining blocks that when broken, can be placed on to damage enemies. Instantly destroys items spawned from breaking block and allows faster placing") + .defaultValue(false) + .visible(place::get) + .build() + ); + + private final Setting forcePlace = sgPlace.add(new EnumSetting.Builder() + .name("Prevent Replace") + .description("Attempts to replace crystals in surrounds") + .defaultValue(ForcePlace.NONE) + .build() + ); + + private final Setting breakValid = sgPlace.add(new BoolSetting.Builder() + .name("Strict") + .description("Only places crystals that can be attacked") + .defaultValue(false) + .visible(place::get) + .build() + ); + + private final Setting strictDirection = sgPlace.add(new BoolSetting.Builder() + .name("Strict Direction") + .description("Interacts with only visible directions when placing crystals") + .defaultValue(false) + .visible(place::get) + .build() + ); + + private final Setting placements = sgPlace.add(new EnumSetting.Builder() + .name("Placements") + .description("Version standard for placing end crystals") + .defaultValue(Placements.NATIVE) + .visible(place::get) + .build() + ); + + private final Setting minDamage = sgDamage.add(new FloatSetting.Builder() + .name("Min Damage") + .description("Minimum damage required to consider attacking or placing an end crystal") + .min(1.0f) + .defaultValue(4.0f) + .max(10.0f) + .build() + ); + + private final Setting maxLocalDamage = sgDamage.add(new FloatSetting.Builder() + .name("Max Local Damage") + .description("The maximum player damage") + .min(4.0f) + .defaultValue(12.0f) + .max(20.0f) + .build() + ); + + private final Setting assumeArmor = sgDamage.add(new BoolSetting.Builder() + .name("Assume Best Armor") + .description("Assumes Prot 0 armor is max armor") + .defaultValue(false) + .build() + ); + + private final Setting armorBreaker = sgDamage.add(new BoolSetting.Builder() + .name("Armor Breaker") + .description("Attempts to break enemy armor with crystals") + .defaultValue(true) + .build() + ); + + private final Setting armorScale = sgDamage.add(new FloatSetting.Builder() + .name("Armor Scale") + .description("Armor damage scale before attempting to break enemy armor with crystals") + .min(1.0f) + .defaultValue(5.0f) + .max(20.0f) + .visible(armorBreaker::get) + .build() + ); + + private final Setting lethalMultiplier = sgDamage.add(new FloatSetting.Builder() + .name("Lethal Multiplier") + .description("If we can kill an enemy with this many crystals, disregard damage values") + .min(0.0f) + .defaultValue(1.5f) + .max(4.0f) + .build() + ); + + private final Setting antiTotem = sgDamage.add(new BoolSetting.Builder() + .name("Lethal Totem") + .description("Predicts totems and places crystals to instantly double pop and kill the target") + .defaultValue(false) + .visible(place::get) + .build() + ); + + private final Setting lethalDamage = sgDamage.add(new BoolSetting.Builder() + .name("Lethal DamageTick") + .description("Places lethal crystals only on ticks where they damage entities") + .defaultValue(false) + .build() + ); + + private final Setting safety = sgDamage.add(new BoolSetting.Builder() + .name("Safety") + .description("Accounts for total player safety when attacking and placing crystals") + .defaultValue(true) + .build() + ); + + private final Setting safetyOverride = sgDamage.add(new BoolSetting.Builder() + .name("Safety Override") + .description("Overrides the safety checks if the crystal will kill an enemy") + .defaultValue(false) + .build() + ); + + private final Setting blockDestruction = sgDamage.add(new BoolSetting.Builder() + .name("Block Destruction") + .description("Accounts for explosion block destruction when calculating damages") + .defaultValue(false) + .build() + ); + + private final Setting selfExtrapolate = sgDamage.add(new BoolSetting.Builder() + .name("Self Extrapolate") + .description("Accounts for motion when calculating self damage") + .defaultValue(false) + .build() + ); + + private final Setting extrapolateTicks = sgDamage.add(new IntSetting.Builder() + .name("Extrapolation Ticks") + .description("Accounts for motion when calculating enemy positions, not fully accurate.") + .min(0) + .defaultValue(0) + .max(10) + .build() + ); + + // Render + + private final Setting render = sgRender.add(new BoolSetting.Builder() + .name("Render") + .description("Renders the current placement") + .defaultValue(true) + .build() + ); + + private final Setting fadeTime = sgRender.add(new IntSetting.Builder() + .name("Fade Time") + .description("Timer for the fade") + .min(0) + .defaultValue(250) + .max(1000) + .build() + ); + + private final Setting disableDeath = sgRender.add(new BoolSetting.Builder() + .name("Disable On Death") + .description("Disables during disconnect/death") + .defaultValue(false) + .build() + ); + + private final Setting color = sgRender.add(new ColorSetting.Builder() + .name("Render Color") + .description("asdsadsadsadsadsa") + .defaultValue(new Color(236, 243, 122, 40)) + .build() + ); + + private final Setting debugDamage = sgRender.add(new BoolSetting.Builder() + .name("Debug Damage") + .description("Renders damage") + .defaultValue(false) + .visible(render::get) + .build() + ); + + private final Setting damageTextScale = sgRender.add(new DoubleSetting.Builder() + .name("damage-scale") + .description("How big the damage text should be.") + .defaultValue(1.25) + .min(1) + .sliderMax(4) + .visible(debugDamage::get) + .build() + ); + + // + private DamageData attackCrystal; + private DamageData placeCrystal; + // + private BlockPos renderPos; + private double renderDamage; + private BlockPos renderSpawnPos; + // + private Vec3d crystalRotation; + private boolean attackRotate; + private boolean rotated; + private float[] silentRotations; + private float calculatePlaceCrystalTime = 0; + // + private static final Box FULL_CRYSTAL_BB = new Box(0.0, 0.0, 0.0, 1.0, 2.0, 1.0); + private static final Box HALF_CRYSTAL_BB = new Box(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + private final CacheTimer lastAttackTimer = new CacheTimer(); + private final Timer lastPlaceTimer = new CacheTimer(); + private final Timer lastSwapTimer = new CacheTimer(); + private final Timer autoSwapTimer = new CacheTimer(); + // default NCP config + // fight.speed: limit: 13 + // shortterm: ticks: 8 + // limitforseconds: half: 8, one: 15, two: 30, four: 60, eight: 100 + private final Deque attackLatency = new EvictingQueue<>(20); + private final Map attackPackets = + Collections.synchronizedMap(new ConcurrentHashMap<>()); + private final Map placePackets = + Collections.synchronizedMap(new ConcurrentHashMap<>()); + private final PerSecondCounter crystalCounter = new PerSecondCounter(); + private final Map fadeList = new HashMap<>(); + private long predictId; + // Antistuck + private final Map antiStuckCrystals = new HashMap<>(); + private final List stuckCrystals = new CopyOnWriteArrayList<>(); + + // Genyo sajkhfjwehfjhwekjfhjkwefew + private final BlockPos.Mutable placeRenderPos = new BlockPos.Mutable(); + private final Vector3d vec3 = new Vector3d(); + private int placeRenderTimer, breakRenderTimer; + + private final ExecutorService executor = Executors.newFixedThreadPool(2); + + /*@Override + public String getModuleData() + { + if (debug.get()) + { + return String.format("%sms, %.0f, %dms, %d".formatted( + new DecimalFormat("0.00") + .format(calculatePlaceCrystalTime / 1E6), + placeCrystal == null ? 0 : lastAttackTimer.getLastResetTime() / 1E6, + lastAttackTimer.passed(((20.0f - breakSpeed.get()) * 50.0f) + 2000.0f) ? 0 : getBreakMs(), + crystalCounter.getPerSecond())); + } + else + { + return String.format("%dms, %d", + lastAttackTimer.passed(((20.0f - breakSpeed.get()) * 50.0f) + 2000.0f) ? 0 : getBreakMs(), + crystalCounter.getPerSecond()); + } + }*/ + + @Override + public void onDeactivate() + { + renderPos = null; + attackCrystal = null; + placeCrystal = null; + crystalRotation = null; + silentRotations = null; + calculatePlaceCrystalTime = 0; + stuckCrystals.clear(); + attackPackets.clear(); + antiStuckCrystals.clear(); + placePackets.clear(); + attackLatency.clear(); + fadeList.clear(); + setStage("NONE"); + } + + @EventHandler + public void onGameLeft(GameLeftEvent event) { + if (disableDeath.get()) + { + this.toggle(); + } + else + { + this.onDeactivate(); + } + } + + @EventHandler + public void onPlayerUpdate(PlayerTickEvent event) + { + if (mc.player.isSpectator() || isSilentSwap(autoSwap.get()) && Modules.get().get(GenyoAutoMine.class).isSilentSwapping()) + { + return; + } + + + for (AntiStuckData d : stuckCrystals) + { + double dist = mc.player.squaredDistanceTo(d.pos()); + double diff = d.stuckDist() - dist; + if (diff > 0.5) + { + stuckCrystals.remove(d); + } + } + + if (mc.player.isUsingItem() && mc.player.getActiveHand() == Hand.MAIN_HAND + || mc.options.attackKey.isPressed() || PlayerUtil.isHotbarKeysPressed()) + { + autoSwapTimer.reset(); + } + renderPos = null; + ArrayList entities = Lists.newArrayList(mc.world.getEntities()); + List blocks = getSphere(placeRangeEye.get() ? mc.player.getEyePos() : mc.player.getPos()); + long timePre = System.nanoTime(); + if (place.get()) + { + placeCrystal = calculatePlaceCrystal(blocks, entities); + } + attackCrystal = calculateAttackCrystal(entities); + if (attackCrystal == null) + { + if (placeCrystal != null) + { + EndCrystalEntity crystalEntity = intersectingCrystalCheck(placeCrystal.getDamageData()); + if (crystalEntity != null) + { + GenyoAddon.LOG.info("fewkjkfewf"); + + double self = ExplosionUtil.getDamageTo(mc.player, crystalEntity.getPos(), + blockDestruction.get(), selfExtrapolate.get() ? extrapolateTicks.get() : 0, false); + if (!safety.get() || !playerDamageCheck(self)) + { + attackCrystal = new DamageData<>(crystalEntity, placeCrystal.getAttackTarget(), + placeCrystal.getDamage(), self, crystalEntity.getBlockPos().down(), false); + } + } + } + calculatePlaceCrystalTime = System.nanoTime() - timePre; + } + + if (inhibit.get() && attackCrystal != null + && attackPackets.containsKey(attackCrystal.getDamageData().getId())) + { + float delay; + if (attackDelay.get() > 0.0) + { + float attackFactor = 50.0f / Math.max(1.0f, attackFactorC.get()); + delay = attackDelay.get() * attackFactor; + } + else + { + delay = 1000.0f - breakSpeed.get() * 50.0f; + } + lastAttackTimer.setDelay(delay + 100.0f); + attackPackets.remove(attackCrystal.getDamageData().getId()); + } + + float breakDelay = getBreakDelay(); + if (breakDelayC.get()) + { + breakDelay = Math.max(minTimeout.get() * 50.0f, getBreakMs() + breakTimeout.get() * 50.0f); + } + attackRotate = attackCrystal != null && attackDelay.get() <= 0.0 && lastAttackTimer.passed(breakDelay); + if (attackCrystal != null) + { + crystalRotation = attackCrystal.damageData.getPos(); + } + else if (placeCrystal != null) + { + crystalRotation = placeCrystal.damageData.toCenterPos().add(0.0, 0.5, 0.0); + } + /*if (rotate.get() && crystalRotation != null && (placeCrystal == null || canHoldCrystal())) + { + float[] rotations = RotationUtil.getRotationsTo(mc.player.getEyePos(), crystalRotation); + if (strictRotate.get() == Rotate.FULL || strictRotate.get() == Rotate.SEMI && attackRotate) + { + float yaw; + float serverYaw = Managers.ROTATION.getWrappedYaw(); + float diff = serverYaw - rotations[0]; + float diff1 = Math.abs(diff); + if (diff1 > 180.0f) + { + diff += diff > 0.0f ? -360.0f : 360.0f; + } + int dir = diff > 0.0f ? -1 : 1; + float deltaYaw = dir * rotateLimit.get(); + if (diff1 > rotateLimit.get()) + { + yaw = serverYaw + deltaYaw; + rotated = false; + } + else + { + yaw = rotations[0]; + rotated = true; + crystalRotation = null; + } + rotations[0] = yaw; + } + else + { + rotated = true; + crystalRotation = null; + } + setRotation(rotations[0], rotations[1]); + } + else + { + silentRotations = null; + } + if (isRotationBlocked() || !rotated && rotate.get()) + { + return; + }*/ +// if (rotateSilent.get() && silentRotations != null) { +// setRotationSilent(silentRotations[0], silentRotations[1]); +// } + final Hand hand = getCrystalHand(); + if (attackCrystal != null) + { + // ChatUtil.clientSendMessage("yaw: " + rotations[0] + ", pitch: " + rotations[1]); + if (attackRotate) + { + // ChatUtil.clientSendMessage("break range:" + Math.sqrt(mc.player.getEyePos().squaredDistanceTo(attackCrystal.getDamageData().getPos()))); + attackCrystal(attackCrystal.getDamageData(), hand); + setStage("ATTACKING"); + lastAttackTimer.reset(); + } + } + boolean placeRotate = lastPlaceTimer.passed(1000.0f - placeSpeed.get() * 50.0f); + if (placeCrystal != null) + { + renderPos = placeCrystal.getDamageData(); + renderDamage = placeCrystal.getDamage(); + if (placeRotate) + { + // ChatUtil.clientSendMessage("place range:" + Math.sqrt(mc.player.getEyePos().squaredDistanceTo(placeCrystal.getDamageData().toCenterPos()))); + placeCrystal(placeCrystal.getDamageData(), hand); + setStage("PLACING"); + lastPlaceTimer.reset(); + } + } + } + + @EventHandler + public void onRunTick(RunTickEvent event) + { + if (mc.player == null) return; + + final Hand hand = getCrystalHand(); + if (attackDelay.get() > 0.0) + { + float attackFactor = 50.0f / Math.max(1.0f, attackFactorC.get()); + if (attackCrystal != null && lastAttackTimer.passed(attackDelay.get() * attackFactor)) + { + attackCrystal(attackCrystal.getDamageData(), hand); + lastAttackTimer.reset(); + } + } + } + + @EventHandler + public void onRender3D(Render3DEvent event) + { + if (render.get()) + { + BlockPos renderPos1 = null; + double factor = 0.0f; + for (Map.Entry set : fadeList.entrySet()) + { + if (set.getKey() == renderPos) + { + continue; + } + + if (set.getValue().getFactor() > factor) + { + renderPos1 = set.getKey(); + factor = set.getValue().getFactor(); + } + + set.getValue().setState(false); + int boxAlpha = (int) (40 * set.getValue().getFactor()); + int lineAlpha = (int) (100 * set.getValue().getFactor()); + + Color boxColor = color.get().a(boxAlpha); + Color lineColor = color.get().a(lineAlpha); + + event.renderer.box(BlockPos.ofFloored(set.getKey().toCenterPos()), boxColor, lineColor, ShapeMode.Both, 0); + } + + /*if (debugDamage.get() && renderPos1 != null) + { + RenderManager.renderSign(String.format("%.1f", renderDamage), + renderPos1.toCenterPos(), new Color(255, 255, 255, (int) (255.0f * factor)).getRGB()); + }*/ + + fadeList.entrySet().removeIf(e -> + e.getValue().getFactor() == 0.0); + + if (renderPos != null && isHoldingCrystal()) + { + Animation animation = new Animation(true, fadeTime.get()); + fadeList.put(renderPos, animation); + } + } + } + + @EventHandler + private void onRender2D(Render2DEvent event) { + if (!debugDamage.get()) return; + //if (placeRenderTimer <= 0 && breakRenderTimer <= 0) return; + + vec3.set(placeRenderPos.getX() + 0.5, placeRenderPos.getY() + 0.5, placeRenderPos.getZ() + 0.5); + + if (NametagUtils.to2D(vec3, damageTextScale.get())) { + NametagUtils.begin(vec3); + TextRenderer.get().begin(1, false, true); + + String text = String.format("%.1f", renderDamage); + double w = TextRenderer.get().getWidth(text) / 2; + TextRenderer.get().render(text, -w, 0, color.get().a(255), true); + + TextRenderer.get().end(); + NametagUtils.end(); + } + } + + @EventHandler(priority = Integer.MAX_VALUE) + public void onPacketReceive(PacketEvent.Receive event) + { + if (mc.player == null || mc.world == null) return; + + if (event.packet instanceof BundleS2CPacket packet) + { + for (Packet packet1 : packet.getPackets()) + { + handleServerPackets(packet1); + } + } + else + { + handleServerPackets(event.packet); + } + } + + private void handleServerPackets(Packet serverPacket) + { + if (serverPacket instanceof ExplosionS2CPacket packet) + { + for (Entity entity : Lists.newArrayList(mc.world.getEntities())) + { + if (entity instanceof EndCrystalEntity && entity.squaredDistanceTo(packet.center().getX(), packet.center().getY(), packet.center().getZ()) < 144.0) + { + mc.executeSync(() -> mc.world.removeEntity(entity.getId(), Entity.RemovalReason.DISCARDED)); + antiStuckCrystals.remove(entity.getId()); + Long attackTime = attackPackets.remove(entity.getId()); + if (attackTime != null) + { + attackLatency.add(System.currentTimeMillis() - attackTime); + } + } + } + } + + if (serverPacket instanceof PlaySoundS2CPacket packet) + { + if (packet.getSound().value() == SoundEvents.ENTITY_GENERIC_EXPLODE.value() && packet.getCategory() == SoundCategory.BLOCKS) + { + for (Entity entity : Lists.newArrayList(mc.world.getEntities())) + { + if (entity instanceof EndCrystalEntity && entity.squaredDistanceTo(packet.getX(), packet.getY(), packet.getZ()) < 144.0) + { + mc.executeSync(() -> mc.world.removeEntity(entity.getId(), Entity.RemovalReason.DISCARDED)); + antiStuckCrystals.remove(entity.getId()); + Long attackTime = attackPackets.remove(entity.getId()); + if (attackTime != null) + { + attackLatency.add(System.currentTimeMillis() - attackTime); + } + } + } + } + } + + if (serverPacket instanceof EntitiesDestroyS2CPacket packet) + { + for (int id : packet.getEntityIds()) + { + antiStuckCrystals.remove(id); + Long attackTime = attackPackets.remove(id); + if (attackTime != null) + { + attackLatency.add(System.currentTimeMillis() - attackTime); + } + } + } + + if (serverPacket instanceof ExperienceOrbSpawnS2CPacket packet && packet.getEntityId() > predictId) + { + predictId = packet.getEntityId(); + } + + if (serverPacket instanceof EntitySpawnS2CPacket packet && packet.getEntityId() > predictId) + { + predictId = packet.getEntityId(); + } + } + + @EventHandler + public void onEntityAdded(EntityAddedEvent event) + { + if (!(event.entity instanceof EndCrystalEntity crystalEntity)) return; + + + Vec3d crystalPos = crystalEntity.getPos(); + BlockPos blockPos = BlockPos.ofFloored(crystalPos.add(0.0, -1.0, 0.0)); + renderSpawnPos = blockPos; + Long time = placePackets.remove(blockPos); + attackRotate = time != null; + if (attackRotate) + { + crystalCounter.updateCounter(); + } + if (!instant.get()) + { + return; + } + if (attackRotate) + { + final Hand hand = getCrystalHand(); + attackInternal(crystalEntity, hand); + setStage("ATTACKING"); + lastAttackTimer.reset(); + if (sequential.get() == Sequential.NORMAL) + { + placeSequentialCrystal(hand); + } + } + else if (instantCalc.get()) + { + if (attackRangeCheck(crystalPos)) + { + return; + } + double selfDamage = ExplosionUtil.getDamageTo(mc.player, crystalPos, + blockDestruction.get(), selfExtrapolate.get() ? extrapolateTicks.get() : 0, false); + if (playerDamageCheck(selfDamage)) + { + return; + } + for (Entity entity : mc.world.getEntities()) + { + if (entity == null || !entity.isAlive() || entity == mc.player + || !isValidTarget(entity) + || (entity instanceof PlayerEntity && Friends.get().isFriend((PlayerEntity) entity))) + { + continue; + } + double crystalDist = crystalPos.squaredDistanceTo(entity.getPos()); + if (crystalDist > 144.0f) + { + continue; + } + double dist = mc.player.squaredDistanceTo(entity); + if (dist > targetRange.get() * targetRange.get()) + { + continue; + } + + double damage = ExplosionUtil.getDamageTo(entity, crystalPos, blockDestruction.get(), + extrapolateTicks.get(), assumeArmor.get()); + // TODO: Test this + DamageData data = new DamageData<>(crystalEntity, + entity, damage, selfDamage, crystalEntity.getBlockPos().down(), false); + attackRotate = damage > instantDamage.get() || attackCrystal != null + && damage >= attackCrystal.getDamage() && instantMax.get() + || entity instanceof LivingEntity entity1 && isCrystalLethalTo(data, entity1); + if (attackRotate) + { + final Hand hand = getCrystalHand(); + attackInternal(crystalEntity, hand); + setStage("ATTACKING"); + lastAttackTimer.reset(); + if (sequential.get() == Sequential.NORMAL) + { + placeSequentialCrystal(hand); + } + break; + } + } + } + } + + @EventHandler + public void onPacketSend(PacketEvent.Send event) + { + if (mc.player == null) return; + + + if (event.packet instanceof UpdateSelectedSlotC2SPacket) + { + lastSwapTimer.reset(); + } + } + + public boolean isAttacking() + { + return attackCrystal != null; + } + + public boolean isPlacing() + { + return placeCrystal != null && isHoldingCrystal(); + } + + public void attackCrystal(EndCrystalEntity entity, Hand hand) + { + if (attackCheckPre(hand)) + { + return; + } + StatusEffectInstance weakness = mc.player.getStatusEffect(StatusEffects.WEAKNESS); + StatusEffectInstance strength = mc.player.getStatusEffect(StatusEffects.STRENGTH); + if (weakness != null && (strength == null || weakness.getAmplifier() > strength.getAmplifier())) + { + int slot = -1; + for (int i = 0; i < 9; ++i) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (!stack.isEmpty() && (stack.getItem() instanceof SwordItem + || stack.getItem() instanceof AxeItem + || stack.getItem() instanceof PickaxeItem)) + { + slot = i; + break; + } + } + if (slot != -1) + { + boolean canSwap = slot != Managers.INVENTORY.getServerSlot() && (antiWeakness.get() != Swap.NORMAL || autoSwapTimer.passed(500)); + if (antiWeakness.get() != Swap.OFF && canSwap) + { + if (antiWeakness.get() == Swap.SILENT_ALT) + { + mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, + slot + 36, mc.player.getInventory().selectedSlot, SlotActionType.SWAP, mc.player); + } + else if (antiWeakness.get() == Swap.SILENT) + { + Managers.INVENTORY.setSlot(slot); + } + else + { + Managers.INVENTORY.setClientSlot(slot); + } + } + attackInternal(entity, Hand.MAIN_HAND); + if (canSwap) + { + if (antiWeakness.get() == Swap.SILENT_ALT) + { + mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, + slot + 36, mc.player.getInventory().selectedSlot, SlotActionType.SWAP, mc.player); + } + else if (antiWeakness.get() == Swap.SILENT) + { + Managers.INVENTORY.syncToClient(); + } + } + + if (sequential.get() == Sequential.STRICT) + { + placeSequentialCrystal(hand); + } + } + } + else + { + attackInternal(entity, hand); + if (sequential.get() == Sequential.STRICT) + { + placeSequentialCrystal(hand); + } + } + } + + private void attackInternal(EndCrystalEntity crystalEntity, Hand hand) + { + attackInternal(crystalEntity.getId(), hand); + } + + private void attackInternal(int crystalEntity, Hand hand) + { + hand = hand != null ? hand : Hand.MAIN_HAND; + EndCrystalEntity entity2 = new EndCrystalEntity(mc.world, 0.0, 0.0, 0.0); + entity2.setId(crystalEntity); + PlayerInteractEntityC2SPacket packet = PlayerInteractEntityC2SPacket.attack(entity2, mc.player.isSneaking()); + mc.getNetworkHandler().sendPacket(packet); + if (swing.get()) + { + mc.player.swingHand(hand); + } + else + { + mc.getNetworkHandler().sendPacket(new HandSwingC2SPacket(hand)); + } + + attackPackets.put(crystalEntity, System.currentTimeMillis()); + Integer antiStuckCount = antiStuckCrystals.get(crystalEntity); + if (antiStuckCount != null) + { + antiStuckCrystals.replace(crystalEntity, antiStuckCount + 1); + } + else + { + antiStuckCrystals.put(crystalEntity, 1); + } + } + + private void placeSequentialCrystal(Hand hand) + { + if (placeCrystal == null) + { + return; + } + int latency = Managers.NETWORK.getClientLatency(); + if (!Managers.NETWORK.is2b2t() || latency >= 50) + { + placeCrystal(placeCrystal.getBlockPos(), hand); + } + } + + private void placeCrystal(BlockPos blockPos, Hand hand) + { + /*if (isRotationBlocked() || !rotated && rotate.get()) + { + return; + }*/ + + placeCrystal(blockPos, hand, true); + } + + public void placeCrystal(BlockPos blockPos, Hand hand, boolean checkPlacement) + { + if (checkPlacement && checkCanUseCrystal()) + { + return; + } + Direction sidePlace = getPlaceDirection(blockPos); + BlockHitResult result = new BlockHitResult(blockPos.toCenterPos(), sidePlace, blockPos, false); + if (autoSwap.get() != Swap.OFF && hand != Hand.OFF_HAND && getCrystalHand() == null) + { + if (isSilentSwap(autoSwap.get()) && InventoryUtil.count(Items.END_CRYSTAL) == 0) + { + return; + } + int crystalSlot = getCrystalSlot(); + if (crystalSlot != -1) + { + boolean canSwap = crystalSlot != Managers.INVENTORY.getServerSlot() && (autoSwap.get() != Swap.NORMAL || autoSwapTimer.passed(500)); + if (canSwap) + { + if (autoSwap.get() == Swap.SILENT_ALT) + { + mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, + crystalSlot + 36, mc.player.getInventory().selectedSlot, SlotActionType.SWAP, mc.player); + } + else if (autoSwap.get() == Swap.SILENT) + { + Managers.INVENTORY.setSlot(crystalSlot); + } + else + { + Managers.INVENTORY.setClientSlot(crystalSlot); + } + } + placeInternal(result, Hand.MAIN_HAND); + + placeRenderPos.set(blockPos); + + placePackets.put(blockPos, System.currentTimeMillis()); + if (canSwap) + { + if (autoSwap.get() == Swap.SILENT_ALT) { + mc.interactionManager.clickSlot(mc.player.playerScreenHandler.syncId, + crystalSlot + 36, mc.player.getInventory().selectedSlot, SlotActionType.SWAP, mc.player); + } else if (autoSwap.get() == Swap.SILENT) { + Managers.INVENTORY.syncToClient(); + } + } + } + } + else if (isHoldingCrystal()) + { + placeInternal(result, hand); + placePackets.put(blockPos, System.currentTimeMillis()); + } + } + + private void placeInternal(BlockHitResult result, Hand hand) + { + if (hand == null) + { + return; + } + Managers.NETWORK.sendSequencedPacket(id -> new PlayerInteractBlockC2SPacket(hand, result, id)); + if (swing.get()) + { + mc.player.swingHand(hand); + } + else + { + Managers.NETWORK.sendPacket(new HandSwingC2SPacket(hand)); + } + + // Entity ID predict + if (idPredict.get()) + { + //boolean flag = AutoXPModule.getInstance().isEnabled() || mc.player.isUsingItem() && mc.player.getStackInHand(mc.player.getActiveHand()).getItem() instanceof ExperienceBottleItem; + boolean flag = mc.player.isUsingItem() && mc.player.getStackInHand(mc.player.getActiveHand()).getItem() instanceof ExperienceBottleItem; + int id = (int) (predictId + 1); + if (flag || attackPackets.containsKey(id)) + { + return; + } + Entity entity = mc.world.getEntityById(id); + if (entity != null && !(entity instanceof EndCrystalEntity)) + { + return; + } + EndCrystalEntity entity2 = new EndCrystalEntity(mc.world, 0.0, 0.0, 0.0); + entity2.setId(id); + PlayerInteractEntityC2SPacket packet = PlayerInteractEntityC2SPacket.attack(entity2, false); + Managers.NETWORK.sendPacket(packet); + Managers.NETWORK.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + attackPackets.put(id, System.currentTimeMillis()); + } + } + + private boolean isSilentSwap(Swap swap) + { + return swap == Swap.SILENT || swap == Swap.SILENT_ALT; + } + + private int getCrystalSlot() + { + int slot = -1; + for (int i = 0; i < 9; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.getItem() instanceof EndCrystalItem) + { + slot = i; + break; + } + } + return slot; + } + + private Direction getPlaceDirection(BlockPos blockPos) + { + int x = blockPos.getX(); + int y = blockPos.getY(); + int z = blockPos.getZ(); + if (strictDirection.get()) + { + if (mc.player.getY() >= blockPos.getY()) + { + return Direction.UP; + } + BlockHitResult result = mc.world.raycast(new RaycastContext( + mc.player.getEyePos(), new Vec3d(x + 0.5, y + 0.5, z + 0.5), + RaycastContext.ShapeType.OUTLINE, + RaycastContext.FluidHandling.NONE, mc.player)); + if (result != null && result.getType() == HitResult.Type.BLOCK) + { + return result.getSide(); + } + } + else + { + if (mc.world.isInBuildLimit(blockPos)) + { + return Direction.DOWN; + } + BlockHitResult result = mc.world.raycast(new RaycastContext( + mc.player.getEyePos(), new Vec3d(x + 0.5, y + 0.5, z + 0.5), + RaycastContext.ShapeType.OUTLINE, + RaycastContext.FluidHandling.NONE, mc.player)); + if (result != null && result.getType() == HitResult.Type.BLOCK) + { + return result.getSide(); + } + } + return Direction.UP; + } + + private DamageData calculateAttackCrystal(List entities) + { + if (entities.isEmpty()) + { + return null; + } + + final List> validData = new ArrayList<>(); + + DamageData data = null; + for (Entity crystal : entities) + { + if (!(crystal instanceof EndCrystalEntity crystal1) || !crystal.isAlive() + || stuckCrystals.stream().anyMatch(d -> d.id() == crystal.getId())) + { + continue; + } + Long time = attackPackets.get(crystal.getId()); + boolean attacked = time != null && time < getBreakMs(); + if ((crystal.age < ticksExisted.get() || attacked) && inhibit.get()) + { + continue; + } + if (attackRangeCheck(crystal1)) + { + continue; + } + double selfDamage = ExplosionUtil.getDamageTo(mc.player, crystal.getPos(), + blockDestruction.get(), selfExtrapolate.get() ? extrapolateTicks.get() : 0, false); + boolean unsafeToPlayer = playerDamageCheck(selfDamage); + if (unsafeToPlayer && !safetyOverride.get()) + { + continue; + } + for (Entity entity : entities) + { + if (entity == null || !entity.isAlive() || entity == mc.player + || !isValidTarget(entity) + || (entity instanceof PlayerEntity && Friends.get().isFriend((PlayerEntity) entity))) + { + continue; + } + double crystalDist = crystal.squaredDistanceTo(entity); + if (crystalDist > 144.0f) + { + continue; + } + double dist = mc.player.squaredDistanceTo(entity); + if (dist > targetRange.get() * targetRange.get()) + { + continue; + } + + boolean antiSurround = false; + if (antiSurroundC.get() && entity instanceof PlayerEntity player + && !BlastResistantBlocks.isUnbreakable(player.getBlockPos())) + { + Set miningPositions = new HashSet<>(); + BlockPos miningBlock = Modules.get().get(GenyoAutoMine.class).getMiningBlock(); + if (Modules.get().get(GenyoAutoMine.class).isActive() && miningBlock != null) + { + miningPositions.add(miningBlock); + } + if (Managers.BLOCK.getMines(0.75f).contains(player.getBlockPos().up())) + { + miningPositions.add(player.getBlockPos().up()); + } + for (BlockPos miningBlockPos : miningPositions) + { + if (!Modules.get().get(GenyoSurroundV2.class).getSurroundNoDown(player).contains(miningBlockPos)) + { + continue; + } + for (Direction direction : Direction.values()) + { + BlockPos pos1 = miningBlockPos.offset(direction); + if (crystal.getBlockPos().equals(pos1.down())) + { + antiSurround = true; + } + } + } + } + + double damage = ExplosionUtil.getDamageTo(entity, crystal.getPos(), blockDestruction.get(), + extrapolateTicks.get(), assumeArmor.get()); + if (checkOverrideSafety(unsafeToPlayer, damage, entity)) + { + continue; + } + + DamageData currentData = new DamageData<>(crystal1, entity, + damage, selfDamage, crystal1.getBlockPos().down(), antiSurround); + validData.add(currentData); + if (data == null || damage > data.getDamage()) + { + data = currentData; + } + } + } + if (data == null || targetDamageCheck(data)) + { + if (antiSurroundC.get()) + { + return validData.stream() + .filter(DamageData::isAntiSurround) + .min(Comparator.comparingDouble(d -> mc.player.squaredDistanceTo(d.getBlockPos().toCenterPos()))) + .orElse(null); + } + return null; + } + return data; + } + + private boolean attackRangeCheck(EndCrystalEntity entity) + { + return attackRangeCheck(entity.getPos()); + } + + /** + * @param entityPos + * @return + */ + private boolean attackRangeCheck(Vec3d entityPos) + { + double breakRange = breakRangeC.get(); + double breakWallRange = breakWallRangeC.get(); + Vec3d playerPos = mc.player.getEyePos(); + double dist = playerPos.squaredDistanceTo(entityPos); + if (dist > breakRange * breakRange) + { + return true; + } + double yOff = Math.abs(entityPos.getY() - mc.player.getY()); + if (yOff > maxYOffset.get()) + { + return true; + } + BlockHitResult result = mc.world.raycast(new RaycastContext( + playerPos, entityPos, RaycastContext.ShapeType.COLLIDER, + RaycastContext.FluidHandling.NONE, mc.player)); + return result.getType() != HitResult.Type.MISS && dist > breakWallRange * breakWallRange; + } + + private DamageData calculatePlaceCrystal(List placeBlocks, List entities) + { + if (placeBlocks.isEmpty() || entities.isEmpty()) + { + return null; + } + + final List> validData = new ArrayList<>(); + + DamageData data = null; + for (BlockPos pos : placeBlocks) + { + if (!canUseCrystalOnBlock(pos) || placeRangeCheck(pos) || intersectingAntiStuckCheck(pos)) + { + continue; + } + double selfDamage = ExplosionUtil.getDamageTo(mc.player, crystalDamageVec(pos), + blockDestruction.get(), selfExtrapolate.get() ? extrapolateTicks.get() : 0, false); + boolean unsafeToPlayer = playerDamageCheck(selfDamage); + if (unsafeToPlayer && !safetyOverride.get()) + { + continue; + } + for (Entity entity : entities) + { + if (entity == null || !entity.isAlive() || entity == mc.player + || !isValidTarget(entity) + || (entity instanceof PlayerEntity && Friends.get().isFriend((PlayerEntity) entity))) + { + continue; + } + double blockDist = pos.getSquaredDistance(entity.getPos()); + if (blockDist > 144.0f) + { + continue; + } + double dist = mc.player.squaredDistanceTo(entity); + if (dist > targetRange.get() * targetRange.get()) + { + continue; + } + + boolean antiSurround = false; + if (antiSurroundC.get() && entity instanceof PlayerEntity player + && !BlastResistantBlocks.isUnbreakable(player.getBlockPos())) + { + Set miningPositions = new HashSet<>(); + BlockPos miningBlock = Modules.get().get(GenyoAutoMine.class).getMiningBlock(); + if (Modules.get().get(GenyoAutoMine.class).isActive() && miningBlock != null) + { + miningPositions.add(miningBlock); + } + if (Managers.BLOCK.getMines(0.75f).contains(player.getBlockPos().up())) + { + miningPositions.add(player.getBlockPos().up()); + } + for (BlockPos miningBlockPos : miningPositions) + { + if (!Modules.get().get(GenyoSurroundV2.class).getSurroundNoDown(player).contains(miningBlockPos)) + { + continue; + } + for (Direction direction : Direction.values()) + { + BlockPos pos1 = miningBlockPos.offset(direction); + if (pos.equals(pos1.down())) + { + antiSurround = true; + } + } + } + } + + double damage; + damage = ExplosionUtil.getDamageTo(entity, crystalDamageVec(pos), blockDestruction.get(), + extrapolateTicks.get(), assumeArmor.get()); + if (checkOverrideSafety(unsafeToPlayer, damage, entity)) + { + continue; + } + + DamageData currentData = new DamageData<>(pos, entity, + damage, selfDamage, antiSurround); + validData.add(currentData); + if (data == null || damage > data.getDamage()) + { + data = currentData; + } + } + } + if (data == null || targetDamageCheck(data)) + { + if (antiSurroundC.get()) + { + return validData.stream() + .filter(DamageData::isAntiSurround) + .min(Comparator.comparingDouble(d -> mc.player.squaredDistanceTo(d.getBlockPos().toCenterPos()))) + .orElse(null); + } + return null; + } + return data; + } + + /** + * @param pos + * @return + */ + private boolean placeRangeCheck(BlockPos pos) + { + double placeRange = placeRangeC.get(); + double placeWallRange = placeWallRangeC.get(); + Vec3d player = placeRangeEye.get() ? mc.player.getEyePos() : mc.player.getPos(); + double dist = placeRangeCenter.get() ? + player.squaredDistanceTo(pos.toCenterPos()) : pos.getSquaredDistance(player.x, player.y, player.z); + if (dist > placeRange * placeRange) + { + return true; + } + Vec3d raytrace = Vec3d.of(pos).add(0.5, 2.70000004768372, 0.5); + BlockHitResult result = mc.world.raycast(new RaycastContext( + mc.player.getEyePos(), raytrace, + RaycastContext.ShapeType.COLLIDER, + RaycastContext.FluidHandling.NONE, mc.player)); + float maxDist = breakRangeC.get() * breakRangeC.get(); + if (result != null && result.getType() == HitResult.Type.BLOCK && !result.getBlockPos().equals(pos)) + { + maxDist = breakWallRangeC.get() * breakWallRangeC.get(); + if (!raytraceC.get() || dist > placeWallRange * placeWallRange) + { + return true; + } + } + return breakValid.get() && dist > maxDist; + } + + public void placeCrystalForTarget(PlayerEntity target, BlockPos blockPos) + { + if (target == null || target.isDead() || placeRangeCheck(blockPos) || !canUseCrystalOnBlock(blockPos)) + { + return; + } + double selfDamage = ExplosionUtil.getDamageTo(mc.player, crystalDamageVec(blockPos), + blockDestruction.get(), Set.of(blockPos), selfExtrapolate.get() ? extrapolateTicks.get() : 0, false); + if (playerDamageCheck(selfDamage)) + { + return; + } + double damage = ExplosionUtil.getDamageTo(target, crystalDamageVec(blockPos), blockDestruction.get(), + Set.of(blockPos), extrapolateTicks.get(), assumeArmor.get()); + if (damage < minDamage.get() && !isCrystalLethalTo(damage, target) + || placeCrystal != null && placeCrystal.getDamage() >= damage) + { + return; + } + + /*float[] rotations = RotationUtil.getRotationsTo(mc.player.getEyePos(), blockPos.toCenterPos()); + setRotation(rotations[0], rotations[1]);*/ + placeCrystal(blockPos, Hand.MAIN_HAND, false); + fadeList.put(blockPos, new Animation(true, fadeTime.get())); + } + + private boolean checkOverrideSafety(boolean unsafeToPlayer, double damage, Entity entity) + { + return safetyOverride.get() && unsafeToPlayer && damage < EntityUtil.getHealth(entity) + 0.5; + } + + private boolean targetDamageCheck(DamageData crystal) + { + double minDmg = minDamage.get(); + if (crystal.getAttackTarget() instanceof LivingEntity entity && isCrystalLethalTo(crystal, entity)) + { + minDmg = 2.0f; + } + return crystal.getDamage() < minDmg; + } + + private boolean playerDamageCheck(double playerDamage) + { + if (!mc.player.isCreative()) + { + float health = mc.player.getHealth() + mc.player.getAbsorptionAmount(); + if (safety.get() && playerDamage >= health + 0.5f) + { + return true; + } + return playerDamage > maxLocalDamage.get(); + } + return false; + } + + private boolean isFeetSurrounded(LivingEntity entity) + { + BlockPos pos1 = entity.getBlockPos(); + if (!mc.world.getBlockState(pos1).isReplaceable()) + { + return true; + } + for (Direction direction : Direction.values()) + { + if (!direction.getAxis().isHorizontal()) + { + continue; + } + BlockPos pos2 = pos1.offset(direction); + if (mc.world.getBlockState(pos2).isReplaceable()) + { + return false; + } + } + return true; + } + + private boolean checkAntiTotem(double damage, LivingEntity entity) + { + if (entity instanceof PlayerEntity p) + { + float phealth = EntityUtil.getHealth(p); + if (phealth <= 2.0f && phealth - damage < 0.5f) + { + long time = Managers.TOTEM.getLastPopTime(p); + if (time != -1) + { + return System.currentTimeMillis() - time <= 500; + } + } + } + return false; + } + + private boolean isCrystalLethalTo(DamageData crystal, LivingEntity entity) + { + return isCrystalLethalTo(crystal.getDamage(), entity); + } + + private boolean isCrystalLethalTo(double damage, LivingEntity entity) + { + if (lethalDamage.get() && lastAttackTimer.passed(500)) + { + return true; + } + + if (antiTotem.get() && checkAntiTotem(damage, entity)) + { + return true; + } + float health = entity.getHealth() + entity.getAbsorptionAmount(); + if (damage * (1.0f + lethalMultiplier.get()) >= health + 0.5f) + { + return true; + } + if (armorBreaker.get()) + { + for (ItemStack armorStack : entity.getArmorItems()) + { + int n = armorStack.getDamage(); + int n1 = armorStack.getMaxDamage(); + float durability = ((n1 - n) / (float) n1) * 100.0f; + if (durability < armorScale.get()) + { + return true; + } + } + } + + // Antiregear + if (shulkers.get() && entity instanceof PlayerEntity) + { + for (BlockPos pos : getSphere(3.0f, entity.getPos())) + { + BlockState state = mc.world.getBlockState(pos); + if (state.getBlock() instanceof ShulkerBoxBlock) + { + return true; + } + } + } + return false; + } + + private boolean attackCheckPre(Hand hand) + { + if (!lastSwapTimer.passed(swapDelay.get() * 25.0f)) + { + return true; + } + if (hand == Hand.MAIN_HAND) + { + return checkCanUseCrystal(); + } + return false; + } + + private boolean checkCanUseCrystal() + { + return !multitask.get() && checkMultitask() + || !whileMining.get() && mc.interactionManager.isBreakingBlock(); + } + + private boolean isHoldingCrystal() + { + if (!checkCanUseCrystal() && (autoSwap.get() == Swap.SILENT || autoSwap.get() == Swap.SILENT_ALT)) + { + return true; + } + return getCrystalHand() != null; + } + + private Vec3d crystalDamageVec(BlockPos pos) + { + return Vec3d.of(pos).add(0.5, 1.0, 0.5); + } + + /** + * Returns true if the {@link Entity} is a valid enemy to attack. + * + * @param e The potential enemy entity + * @return true if the entity is an enemy + */ + private boolean isValidTarget(Entity e) + { + return e instanceof PlayerEntity && players.get() + || EntityUtil.isMonster(e) && monsters.get() + || EntityUtil.isNeutral(e) && neutrals.get() + || EntityUtil.isPassive(e) && animals.get(); + } + + /** + * Returns true if an {@link EndCrystalItem} can be used on the + * param {@link BlockPos}. + * + * @param pos The block pos + * @return Returns true if the crystal item can be placed on the + * block + */ + public boolean canUseCrystalOnBlock(BlockPos pos) + { + BlockState state = mc.world.getBlockState(pos); + if (!state.isOf(Blocks.OBSIDIAN) && !state.isOf(Blocks.BEDROCK)) + { + return false; + } + return isCrystalHitboxClear(pos); + } + + public boolean isCrystalHitboxClear(BlockPos pos) + { + BlockPos p2 = pos.up(); + BlockState state2 = mc.world.getBlockState(p2); + // ver 1.12.2 and below + if (placements.get() == Placements.PROTOCOL && !mc.world.isAir(p2.up())) + { + return false; + } + if (!mc.world.isAir(p2) && !state2.isOf(Blocks.FIRE)) + { + return false; + } + else + { + final Box bb = Managers.NETWORK.isCrystalPvpCC() ? HALF_CRYSTAL_BB : FULL_CRYSTAL_BB; + double d = p2.getX(); + double e = p2.getY(); + double f = p2.getZ(); + List list = getEntitiesBlockingCrystal(new Box(d, e, f, + d + bb.maxX, e + bb.maxY, f + bb.maxZ)); + return list.isEmpty(); + } + } + + private List getEntitiesBlockingCrystal(Box box) + { + List entities = new CopyOnWriteArrayList<>( + mc.world.getOtherEntities(null, box)); + // + for (Entity entity : entities) + { + if (entity == null || !entity.isAlive() + || entity instanceof ExperienceOrbEntity + || forcePlace.get() != ForcePlace.NONE + && entity instanceof ItemEntity && entity.age <= 10) + { + entities.remove(entity); + } + else if (entity instanceof EndCrystalEntity entity1 + && entity1.getBoundingBox().intersects(box)) + { + Integer antiStuckAttacks = antiStuckCrystals.get(entity1.getId()); + if (!attackRangeCheck(entity1) && (antiStuckAttacks == null || antiStuckAttacks <= attackLimit.get() * 10.0f)) + { + entities.remove(entity); + } + else + { + double dist = mc.player.squaredDistanceTo(entity1); + stuckCrystals.add(new AntiStuckData(entity1.getId(), entity1.getBlockPos(), entity1.getPos(), dist)); + } + } + } + return entities; + } + + private boolean intersectingAntiStuckCheck(BlockPos blockPos) + { + if (stuckCrystals.isEmpty()) + { + return false; + } + return stuckCrystals.stream().anyMatch(d -> d.blockPos().equals(blockPos.up())); + } + + private EndCrystalEntity intersectingCrystalCheck(BlockPos pos) + { + return (EndCrystalEntity) mc.world.getOtherEntities(null, new Box(pos)).stream() + .filter(e -> e instanceof EndCrystalEntity).min(Comparator.comparingDouble(e -> mc.player.distanceTo(e))).orElse(null); + } + + private List getSphere(Vec3d origin) + { + double rad = Math.ceil(placeRangeC.get()); + return getSphere(rad, origin); + } + + private List getSphere(double rad, Vec3d origin) + { + List sphere = new ArrayList<>(); + for (double x = -rad; x <= rad; ++x) + { + for (double y = -rad; y <= rad; ++y) + { + for (double z = -rad; z <= rad; ++z) + { + Vec3i pos = new Vec3i((int) (origin.getX() + x), + (int) (origin.getY() + y), (int) (origin.getZ() + z)); + final BlockPos p = new BlockPos(pos); + sphere.add(p); + } + } + } + return sphere; + } + + private boolean canHoldCrystal() + { + return isHoldingCrystal() || autoSwap.get() != Swap.OFF && getCrystalSlot() != -1; + } + + private Hand getCrystalHand() + { + final ItemStack offhand = mc.player.getOffHandStack(); + final ItemStack mainhand = mc.player.getMainHandStack(); + if (offhand.getItem() instanceof EndCrystalItem) + { + return Hand.OFF_HAND; + } + else if (mainhand.getItem() instanceof EndCrystalItem) + { + return Hand.MAIN_HAND; + } + return null; + } + + public float getBreakDelay() + { + return 1000.0f - breakSpeed.get() * 50.0f; + } + + // Debug info + public void setStage(String crystalStage) + { + // this.crystalStage = crystalStage; + } + + public int getBreakMs() + { + if (attackLatency.isEmpty()) + { + return 0; + } + float avg = 0.0f; + // fix ConcurrentModificationException + ArrayList latencyCopy = Lists.newArrayList(attackLatency); + if (!latencyCopy.isEmpty()) + { + for (float t : latencyCopy) + { + avg += t; + } + avg /= latencyCopy.size(); + } + return (int) avg; + } + + public boolean shouldPreForcePlace() + { + return forcePlace.get() == ForcePlace.PRE; + } + + public float getPlaceRange() + { + return placeRangeC.get(); + } + + public enum Swap + { + NORMAL, + SILENT, + SILENT_ALT, + OFF + } + + public enum Sequential + { + NORMAL, + STRICT, + NONE + } + + public enum ForcePlace + { + PRE, + POST, + NONE + } + + public enum Placements + { + NATIVE, + PROTOCOL + } + + public enum Rotate + { + FULL, + SEMI, + OFF + } + + private record AntiStuckData(int id, BlockPos blockPos, Vec3d pos, double stuckDist) {} + + private static class DamageData + { + // + private final List tags = new ArrayList<>(); + private T damageData; + private Entity attackTarget; + private BlockPos blockPos; + // + private double damage, selfDamage; + private boolean antiSurround; + + // + public DamageData() + { + + } + + public DamageData(BlockPos damageData, Entity attackTarget, double damage, + double selfDamage, boolean antiSurround) + { + this.damageData = (T) damageData; + this.attackTarget = attackTarget; + this.damage = damage; + this.selfDamage = selfDamage; + this.blockPos = damageData; + this.antiSurround = antiSurround; + } + + public DamageData(T damageData, Entity attackTarget, double damage, + double selfDamage, BlockPos blockPos, boolean antiSurround) + { + this.damageData = damageData; + this.attackTarget = attackTarget; + this.damage = damage; + this.selfDamage = selfDamage; + this.blockPos = blockPos; + this.antiSurround = antiSurround; + } + + public void setDamageData(T damageData, Entity attackTarget, double damage, double selfDamage) + { + this.damageData = damageData; + this.attackTarget = attackTarget; + this.damage = damage; + this.selfDamage = selfDamage; + } + + public T getDamageData() + { + return damageData; + } + + public Entity getAttackTarget() + { + return attackTarget; + } + + public double getDamage() + { + return damage; + } + + public double getSelfDamage() + { + return selfDamage; + } + + public BlockPos getBlockPos() + { + return blockPos; + } + + public boolean isAntiSurround() + { + return antiSurround; + } + } + + private class AttackCrystalTask implements Callable> + { + private final List threadSafeEntities; + + public AttackCrystalTask(List threadSafeEntities) + { + this.threadSafeEntities = threadSafeEntities; + } + + @Override + public DamageData call() throws Exception + { + return calculateAttackCrystal(threadSafeEntities); + } + } + + private class PlaceCrystalTask implements Callable> + { + private final List threadSafeBlocks; + private final List threadSafeEntities; + + public PlaceCrystalTask(List threadSafeBlocks, + List threadSafeEntities) + { + this.threadSafeBlocks = threadSafeBlocks; + this.threadSafeEntities = threadSafeEntities; + } + + @Override + public DamageData call() throws Exception + { + return calculatePlaceCrystal(threadSafeBlocks, threadSafeEntities); + } + } + +} diff --git a/src/main/java/com/genyo/addon/modules/combat/GenyoAutoTotem.java b/src/main/java/com/genyo/addon/modules/combat/GenyoAutoTotem.java new file mode 100644 index 0000000..a48b457 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/combat/GenyoAutoTotem.java @@ -0,0 +1,433 @@ +package com.genyo.addon.modules.combat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.meteor.SettingChangedEvent; +import com.genyo.addon.events.world.LoadWorldEvent; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.settings.FloatSetting; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.genyo.addon.utils.player.InventoryUtil; +import com.genyo.addon.utils.player.PlayerUtil; +import com.genyo.addon.utils.world.ExplosionUtil; +import com.genyo.addon.utils.world.SneakBlocks; +import com.google.common.collect.Lists; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.EndCrystalEntity; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.item.*; +import net.minecraft.network.packet.s2c.play.HealthUpdateS2CPacket; +import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.Text; +import net.minecraft.util.hit.BlockHitResult; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class GenyoAutoTotem extends GenyoModule { + + public GenyoAutoTotem() { + super(GenyoAddon.GENYO, "genyo-auto-totem", "Automatically replenishes the totem in your offhand"); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting itemConfig = sgGeneral.add(new EnumSetting.Builder() + .name("Item") + .description("The item to wield in your offhand") + .defaultValue(OffhandItem.TOTEM) + .build() + ); + + private final Setting healthConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Health") + .description("The health required to fall below before swapping to a totem") + .min(0.0f) + .defaultValue(14.0f) + .max(20.0f) + .build() + ); + + private final Setting gappleConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Offhand Gapple") + .description("Equips a golden apple if holding down the item use button") + .defaultValue(true) + .build() + ); + + private final Setting crappleConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Crapple") + .description("Uses a normal golden apple if Absorption is present") + .defaultValue(true) + .build() + ); + + private final Setting lethalConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Lethal") + .description("Calculates lethal damage sources") + .defaultValue(false) + .visible(() -> itemConfig.get() != OffhandItem.TOTEM) + .build() + ); + + private final Setting fastConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Fast Swap") + .description("Swaps items to offhand") + .defaultValue(true) + .build() + ); + + private final Setting mainhandTotemConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Mainhand Totem") + .description("Swaps to a totem in your mainhand") + .defaultValue(false) + .build() + ); + + private final Setting totemSlotConfig = sgGeneral.add(new IntSetting.Builder() + .name("Totem Slot") + .description("Slot to use for mainhand totem") + .min(1) + .defaultValue(1) + .max(9) + .visible(mainhandTotemConfig::get) + .build() + ); + + private final Setting alternativeConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Alternative") + .description("Replaces totem using the swap packet") + .defaultValue(false) + .build() + ); + + private final Setting debugConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Debug") + .description("Debug on death") + .defaultValue(false) + .build() + ); + + private int lastHotbarSlot, lastTotemCount; + private Item lastHotbarItem; + private Item offhandItem; + private boolean replacing; + private long replaceTime; + + private final Timer mainhandSwapTimer = new CacheTimer(); + private boolean totemInMainhand; + + @Override + public void onDeactivate() + { + lastHotbarSlot = -1; + lastHotbarItem = null; + offhandItem = null; + totemInMainhand = false; + } + + @EventHandler + public void onLoadWorld(LoadWorldEvent event) { + lastTotemCount = InventoryUtil.count(Items.TOTEM_OF_UNDYING); + } + + @EventHandler(priority = Integer.MAX_VALUE - 1) + public void onTick(TickEvent.Pre event) + { + if (mc.player == null) return; + + if (mainhandTotemConfig.get() && mainhandSwapTimer.passed(200)) + { + int totemSlot1 = totemSlotConfig.get() - 1; + ItemStack totemSlotStack = mc.player.getInventory().getStack(totemSlot1); + totemSlot1 += 36; + if (totemSlotStack.getItem() != Items.TOTEM_OF_UNDYING) + { + int n = 35; + while (n >= 0) + { + if (mc.player.getInventory().getStack(n).getItem() == Items.TOTEM_OF_UNDYING) + { + int slot = n < 9 ? n + 36 : n; + replacing = true; + if (alternativeConfig.get()) + { + mc.interactionManager.clickSlot(0, slot, totemSlot1, SlotActionType.SWAP, mc.player); + replacing = false; + } + else + { + if (mc.player.currentScreenHandler.getCursorStack().getItem() != Items.TOTEM_OF_UNDYING) + { + mc.interactionManager.clickSlot(0, slot, 0, SlotActionType.PICKUP, mc.player); + } + if (mc.player.currentScreenHandler.getCursorStack().getItem() == Items.TOTEM_OF_UNDYING) + { + mc.interactionManager.clickSlot(0, totemSlot1, 0, SlotActionType.PICKUP, mc.player); + lastTotemCount = InventoryUtil.count(Items.TOTEM_OF_UNDYING) - 1; + } + replacing = false; + if (!mc.player.currentScreenHandler.getCursorStack().isEmpty() && mc.player.getOffHandStack().getItem() == Items.TOTEM_OF_UNDYING) + { + mc.interactionManager.clickSlot(0, slot, 0, SlotActionType.PICKUP, mc.player); + return; + } + } + } + n--; + } + } + + totemInMainhand = checkMainhandTotem(); + if (totemInMainhand) + { + int totemSlot = -1; + for (int i = 0; i < 9; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.getItem() == Items.TOTEM_OF_UNDYING) + { + totemSlot = i; + break; + } + } + if (totemSlot != -1) + { + Managers.INVENTORY.setClientSlot(totemSlot); + } + } + } + else + { + totemInMainhand = false; + } + + offhandItem = itemConfig.get().getItem(); + if (checkLethal()) + { + offhandItem = Items.TOTEM_OF_UNDYING; + } + else + { + // If offhand gap is enabled & the use key is pressed down, equip a golden apple. + final Item mainHandItem = mc.player.getMainHandStack().getItem(); + if (gappleConfig.get() && mc.options.useKey.isPressed() + && (mainHandItem instanceof SwordItem + || mainHandItem instanceof TridentItem + || mainHandItem instanceof AxeItem) + && PlayerUtil.getLocalPlayerHealth() >= healthConfig.get()) + { + if (mc.crosshairTarget instanceof BlockHitResult result) + { + BlockState interactBlock = mc.world.getBlockState(result.getBlockPos()); + if (!SneakBlocks.isSneakBlock(interactBlock)) + { + offhandItem = getGoldenAppleType(); + } + } + else + { + offhandItem = getGoldenAppleType(); + } + } + } + + if (mc.player.getOffHandStack().getItem() == offhandItem) + { + return; + } + int n = 35; + if (lastHotbarSlot != -1 && lastHotbarItem != null) + { + final ItemStack stack = mc.player.getInventory().getStack(lastHotbarSlot); + if (stack.getItem().equals(offhandItem) && lastHotbarItem.equals(mc.player.getOffHandStack().getItem())) + { + final int tmp = lastHotbarSlot; + lastHotbarSlot = -1; + lastHotbarItem = null; + n = tmp; + } + } + while (n >= 0) + { + if (mc.player.getInventory().getStack(n).getItem() == offhandItem) + { + if (n < 9) + { + lastHotbarItem = offhandItem; + lastHotbarSlot = n; + } + int slot = n < 9 ? n + 36 : n; + replacing = true; + if (alternativeConfig.get()) + { + mc.interactionManager.clickSlot(0, slot, 40, SlotActionType.SWAP, mc.player); + replacing = false; + } + else + { + if (mc.player.currentScreenHandler.getCursorStack().getItem() != offhandItem) + { + mc.interactionManager.clickSlot(0, slot, 0, SlotActionType.PICKUP, mc.player); + } + if (mc.player.currentScreenHandler.getCursorStack().getItem() == offhandItem) + { + mc.interactionManager.clickSlot(0, 45, 0, SlotActionType.PICKUP, mc.player); + lastTotemCount = InventoryUtil.count(Items.TOTEM_OF_UNDYING) - 1; + } + replacing = false; + if (!mc.player.currentScreenHandler.getCursorStack().isEmpty() && mc.player.getOffHandStack().getItem() == offhandItem) + { + mc.interactionManager.clickSlot(0, slot, 0, SlotActionType.PICKUP, mc.player); + return; + } + } + } + n--; + } + } + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) { + if (mc.player == null || mc.world == null) return; + + if (event.packet instanceof HealthUpdateS2CPacket packet + && packet.getHealth() <= 0.0f && debugConfig.get()) + { + if (lastTotemCount <= 0) return; + + final Set failureReasonsSet = getFailureReasons(); + if (failureReasonsSet.isEmpty()) + { + long serverLatency = System.currentTimeMillis() - replaceTime; + sendError("Failed to replace totem in " + serverLatency + "ms!"); + } + else + { + sendError("Failed to replace totem! Possible reasons: " + String.join(", ", failureReasonsSet)); + } + } + // Server should only send this when we pop a totem + if (event.packet instanceof ScreenHandlerSlotUpdateS2CPacket packet + && packet.getSlot() == 45 && offhandItem == Items.TOTEM_OF_UNDYING) + { + if (mc.player.getOffHandStack().getItem() != Items.TOTEM_OF_UNDYING || !packet.getStack().isEmpty()) + { + return; + } + replaceTime = System.currentTimeMillis(); + } + } + + private Set getFailureReasons() + { + final Set failureReasonsSet = new LinkedHashSet<>(); + if (mc.player.currentScreenHandler.syncId != 0) + { + failureReasonsSet.add("Current screen handler is not the player inventory"); + } + if (!mc.player.currentScreenHandler.getCursorStack().isEmpty()) + { + failureReasonsSet.add("Totem was not placed in offhand on time"); + } + return failureReasonsSet; + } + + @EventHandler + public void onConfigUpdate(SettingChangedEvent event) + { + if (event.setting == totemSlotConfig) + { + mainhandSwapTimer.reset(); + } + } + + private boolean checkLethal() + { + // If the player's health (+absorption) falls below the "safe" amount, equip a totem + final float health = PlayerUtil.getLocalPlayerHealth(); + return health <= healthConfig.get() || lethalConfig.get() && checkLethalCrystal(health) || + PlayerUtil.computeFallDamage(mc.player.fallDistance, 1.0f) + 0.5f > mc.player.getHealth(); + } + + private boolean checkLethalCrystal(float health) + { + final List entities = Lists.newArrayList(mc.world.getEntities()); + for (Entity e : entities) + { + if (e == null || !e.isAlive() || !(e instanceof EndCrystalEntity crystal)) + { + continue; + } + if (mc.player.squaredDistanceTo(e) > 144.0) + { + continue; + } + double potential = ExplosionUtil.getDamageTo(mc.player, crystal.getPos(), false); + if (health + 0.5 > potential) + { + continue; + } + return true; + } + + return false; + } + + private Item getGoldenAppleType() + { + if (crappleConfig.get() && InventoryUtil.hasItemInInventory(Items.GOLDEN_APPLE, true) + && (mc.player.hasStatusEffect(StatusEffects.ABSORPTION) + || !InventoryUtil.hasItemInInventory(Items.ENCHANTED_GOLDEN_APPLE, true))) + { + return Items.GOLDEN_APPLE; + } + return Items.ENCHANTED_GOLDEN_APPLE; + } + + private boolean checkMainhandTotem() + { + if (mc.player.getMainHandStack().getItem() == Items.TOTEM_OF_UNDYING) + { + return false; + } + return checkLethalCrystal(PlayerUtil.getLocalPlayerHealth()); + } + + public boolean isTotemInMainhand() + { + return totemInMainhand; + } + + public boolean isReplacing() + { + return replacing; + } + + private enum OffhandItem + { + TOTEM(Items.TOTEM_OF_UNDYING), + GAPPLE(Items.ENCHANTED_GOLDEN_APPLE), + CRYSTAL(Items.END_CRYSTAL); + + private final Item item; + + OffhandItem(Item item) + { + this.item = item; + } + + public Item getItem() + { + return item; + } + } +} diff --git a/src/main/java/com/genyo/addon/modules/combat/GenyoCriticals.java b/src/main/java/com/genyo/addon/modules/combat/GenyoCriticals.java new file mode 100644 index 0000000..21a1783 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/combat/GenyoCriticals.java @@ -0,0 +1,343 @@ +package com.genyo.addon.modules.combat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.modules.world.GenyoAutoMine; +import com.genyo.addon.modules.world.GenyoSelfTrap; +import com.genyo.addon.modules.world.GenyoSurroundV2; +import com.genyo.addon.utils.GEntityUtils; +import com.genyo.addon.utils.math.GPositionUtils; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.genyo.addon.utils.player.InventoryUtil; +import com.genyo.addon.utils.player.MovementUtil; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.mixininterface.IPlayerInteractEntityC2SPacket; +import meteordevelopment.meteorclient.settings.BoolSetting; +import meteordevelopment.meteorclient.settings.EnumSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; + +public class GenyoCriticals extends GenyoModule { + + public GenyoCriticals() { + super(GenyoAddon.GENYO, "genyo-criticals", "crrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting multitaskConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Multitask") + .description("Allows crits when other combat modules are enabled") + .defaultValue(true) + .build() + ); + + private final Setting modeConfig = sgGeneral.add(new EnumSetting.Builder() + .name("Mode") + .description("Mode for critical attack modifier") + .defaultValue(CritMode.PACKET) + .build() + ); + + private final Setting phaseOnlyConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Phased Only") + .description("Only attempts criticals when phased") + .defaultValue(false) + .visible(() -> modeConfig.get() == CritMode.GRIM_V3 || modeConfig.get() == CritMode.GRIM) + .build() + ); + + private final Setting wallsOnlyConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Walls Only") + .description("Only attempts criticals in walls") + .defaultValue(false) + .visible(() -> (modeConfig.get() == CritMode.GRIM_V3 || modeConfig.get() == CritMode.GRIM) && phaseOnlyConfig.get()) + .build() + ); + + private final Setting moveFixConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Move Fix") + .description("Pauses crits when moving") + .defaultValue(false) + .visible(() -> modeConfig.get() == CritMode.GRIM_V3 || modeConfig.get() == CritMode.GRIM) + .build() + ); + + // + private final Timer attackTimer = new CacheTimer(); + private boolean postUpdateGround; + private boolean postUpdateSprint; + + @Override + public void onDeactivate() + { + postUpdateGround = false; + postUpdateSprint = false; + } + + /** + * @param event + */ + @EventHandler + public void onPacketSend(PacketEvent.Send event) + { + // Custom aura crit handling + if (mc.player == null || mc.world == null) return; + + if (Modules.get().get(GenyoAutoCrystal.class).isAttacking() || Modules.get().get(GenyoAutoCrystal.class).isPlacing()) + { + return; + } + + // All combat modules have priority + if (!multitaskConfig.get() && (Modules.get().get(GenyoSurroundV2.class).isPlacing() + || Modules.get().get(GenyoSelfTrap.class).isPlacing() + || Modules.get().isActive(GenyoAutoMine.class))) + { + return; + } + + if (event.packet instanceof IPlayerInteractEntityC2SPacket packet + && packet.meteor$getType() == PlayerInteractEntityC2SPacket.InteractType.ATTACK) + { + if (mc.player.isRiding() + || mc.player.isTouchingWater() + || mc.player.isInLava() + || mc.player.isHoldingOntoLadder() + || mc.player.hasStatusEffect(StatusEffects.BLINDNESS) + || InventoryUtil.isHolding32k()) + { + return; + } + + // Attacked entity + final Entity e = packet.meteor$getEntity(); + if (e == null || !e.isAlive() || !(e instanceof LivingEntity)) + { + return; + } + if (GEntityUtils.isVehicle(e)) + { + if (modeConfig.get() == CritMode.PACKET) + { + for (int i = 0; i < 5; ++i) + { + Managers.NETWORK.sendQuietPacket(PlayerInteractEntityC2SPacket.attack(e, + Managers.POSITION.isSneaking())); + Managers.NETWORK.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + } + } + return; + } + + postUpdateSprint = mc.player.isSprinting(); + if (postUpdateSprint) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.STOP_SPRINTING)); + } + + attackSpoofJump(e); + } + } + + + public void attackSpoofJump(Entity e) + { + double x = Managers.POSITION.getX(); + double y = Managers.POSITION.getY(); + double z = Managers.POSITION.getZ(); + switch (modeConfig.get()) + { + case VANILLA -> + { + if (mc.player.isOnGround() && !mc.player.input.playerInput.jump()) + { + double d = 1.0e-7 + 1.0e-7 * (1.0 + RANDOM.nextInt(RANDOM.nextBoolean() ? 34 : 43)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 0.1016f + d * 3.0f, z, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 0.0202f + d * 2.0f, z, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 3.239e-4 + d, z, false, mc.player.horizontalCollision)); + mc.player.addCritParticles(e); + } + } + case PACKET -> + { + if (mc.player.isOnGround() && !mc.player.input.playerInput.jump()) + { + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 0.0625f, z, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y, z, false, mc.player.horizontalCollision)); + mc.player.addCritParticles(e); + } + } + case PACKET_STRICT -> + { + if (attackTimer.passed(500) && mc.player.isOnGround() && !mc.player.input.playerInput.jump()) + { + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 1.1e-7f, z,false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( + x, y + 1.0e-8f, z, false, mc.player.horizontalCollision)); + postUpdateGround = true; + attackTimer.reset(); + } + } + case GRIM -> + { + if (phaseOnlyConfig.get() && (wallsOnlyConfig.get() ? !isDoublePhased() : !isPhased())) + { + return; + } + + if (moveFixConfig.get() && MovementUtil.isMovingInput()) + { + return; + } + + if (attackTimer.passed(250) && mc.player.isOnGround() && !mc.player.isCrawling()) + { + float yaw = Managers.ROTATION.getServerYaw(); + float pitch = Managers.ROTATION.getServerPitch(); + if (Managers.ROTATION.isRotating()) + { + yaw = Managers.ROTATION.getRotationYaw(); + pitch = Managers.ROTATION.getRotationPitch(); + } + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y + 0.0625, z, yaw, pitch, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y + 0.0625013579, z, yaw, pitch, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y + 1.3579e-6, z, yaw, pitch, false, mc.player.horizontalCollision)); + attackTimer.reset(); + } +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( +// x, y + 0.00150000001304f, z, mc.player.getYaw(), mc.player.getPitch(), false)); +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( +// x, y + 0.014400000001304f, z, mc.player.getYaw(), mc.player.getPitch(), false)); +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( +// x, y + 0.001150000001304f, z, mc.player.getYaw(), mc.player.getPitch(), false)); + } + case GRIM_V3 -> + { + if (phaseOnlyConfig.get() && (wallsOnlyConfig.get() ? !isDoublePhased() : !isPhased())) + { + return; + } + + if (moveFixConfig.get() && MovementUtil.isMovingInput()) + { + return; + } + + if (mc.player.isOnGround() && !mc.player.isCrawling()) + { +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( +// x, y + 0.00001058293536f, z, false)); +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( +// x, y + 0.00000916580235f, z, false)); +// Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround( +// x, y + 0.00000010371854f, z, false)); + float yaw = Managers.ROTATION.getServerYaw(); + float pitch = Managers.ROTATION.getServerPitch(); + if (Managers.ROTATION.isRotating()) + { + yaw = Managers.ROTATION.getRotationYaw(); + pitch = Managers.ROTATION.getRotationPitch(); + } + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y, z, yaw, pitch, true, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y + 0.0625f, z, yaw, pitch, false, mc.player.horizontalCollision)); + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.Full( + x, y + 0.04535f, z, yaw, pitch, false, mc.player.horizontalCollision)); + } + } + case LOW_HOP -> + { + // mc.player.jump(); + Managers.MOVEMENT.setMotionY(0.3425); + } + } + } + + @EventHandler + public void onPacketSent(PacketEvent.Sent event) { + if (mc.player == null) return; + + if (event.packet instanceof PlayerInteractEntityC2SPacket) + { + if (postUpdateGround) + { + Managers.NETWORK.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(mc.player.getX(), mc.player.getY(), mc.player.getZ(), false, mc.player.horizontalCollision)); + postUpdateGround = false; + } + + if (postUpdateSprint) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_SPRINTING)); + postUpdateSprint = false; + } + } + } + + public boolean isGrim() + { + return modeConfig.get() == CritMode.GRIM; + } + + public boolean isDoublePhased() + { + for (BlockPos pos : GPositionUtils.getAllInBox(mc.player.getBoundingBox(), mc.player.getBlockPos())) + { + BlockState state = mc.world.getBlockState(pos); + BlockState state2 = mc.world.getBlockState(pos.up()); + if (state.blocksMovement() && state2.blocksMovement()) + { + return true; + } + } + return false; + } + + public boolean isPhased() + { + for (BlockPos pos : GPositionUtils.getAllInBox(mc.player.getBoundingBox())) + { + if (mc.world.getBlockState(pos).blocksMovement()) + { + return true; + } + } + + return false; + } + + public enum CritMode + { + PACKET, + PACKET_STRICT, + VANILLA, + GRIM, + GRIM_V3, + LOW_HOP + } + +} diff --git a/src/main/java/com/genyo/addon/modules/combat/GenyoReplenish.java b/src/main/java/com/genyo/addon/modules/combat/GenyoReplenish.java new file mode 100644 index 0000000..6f9404d --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/combat/GenyoReplenish.java @@ -0,0 +1,196 @@ +package com.genyo.addon.modules.combat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.entity.EntityDeathEvent; +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.events.network.PlayerTickEvent; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.genyo.addon.utils.player.InventoryUtil; +import meteordevelopment.meteorclient.settings.BoolSetting; +import meteordevelopment.meteorclient.settings.IntSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.client.gui.screen.ingame.InventoryScreen; +import net.minecraft.client.gui.screen.ingame.ShulkerBoxScreen; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.slot.SlotActionType; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class GenyoReplenish extends GenyoModule { + + public GenyoReplenish() { + super(GenyoAddon.GENYO, "genyo-replenish", "fwejhfkljwefklwejfklkwlefjlwefl"); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting percentConfig = sgGeneral.add(new IntSetting.Builder() + .name("Percent") + .description("The minimum percent of total stack before replenishing") + .min(1) + .defaultValue(25) + .max(80) + .build() + ); + + private final Setting resistantConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Allow Resistant") + .description("Refills obsidian with other types of resistant blocks") + .defaultValue(false) + .build() + ); + + // Cached hotbar in case the hotbar slot becomes empty + private final Map hotbarCache = new ConcurrentHashMap<>(); + + private final Timer lastDroppedTimer = new CacheTimer(); + + @Override + public void onDeactivate() + { + hotbarCache.clear(); + } + + @EventHandler + public void onDisconnect(DisconnectEvent event) + { + hotbarCache.clear(); + } + + @EventHandler + public void onEntityDeath(EntityDeathEvent event) + { + if (event.entity instanceof ClientPlayerEntity) + { + hotbarCache.clear(); + } + } + + @EventHandler + public void onTick(PlayerTickEvent event) + { + if (mc.options.dropKey.isPressed()) + { + lastDroppedTimer.reset(); + } + + boolean pauseReplenish = isInInventoryScreen() || !lastDroppedTimer.passed(100); + + if (!pauseReplenish) + { + for (int i = 0; i < 9; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.isEmpty()) + { + ItemStack cachedStack = hotbarCache.getOrDefault(i, null); + if (cachedStack != null && !cachedStack.isEmpty()) + { + replenishStack(i, cachedStack); + break; + } + continue; + } + + if (!stack.isStackable()) + { + continue; + } + + double percentage = ((double) stack.getCount() / stack.getMaxCount()) * 100.0; + if (percentage <= percentConfig.get()) + { + replenishStack(i, stack); + break; + } + } + } + + for (int i = 0; i < 9; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.isEmpty() && !pauseReplenish) + { + continue; + } + + if (hotbarCache.containsKey(i)) + { + hotbarCache.replace(i, stack.copy()); + } + else + { + hotbarCache.put(i, stack.copy()); + } + } + } + + public boolean isInInventoryScreen() + { + return mc.currentScreen instanceof GenericContainerScreen || mc.currentScreen instanceof ShulkerBoxScreen || mc.currentScreen instanceof InventoryScreen; + } + + private void replenishStack(int slot, ItemStack stack) + { + int slot1 = -1; + boolean outOfObsidian = stack.getItem() == Items.OBSIDIAN && InventoryUtil.count(Items.OBSIDIAN) <= 1; + for (int i = 9; i < 36; ++i) + { + ItemStack itemStack = mc.player.getInventory().getStack(i); + + if (itemStack.isEmpty()) + { + continue; + } + + if (!isSame(stack, itemStack, outOfObsidian) || !itemStack.isStackable()) + { + continue; + } + + slot1 = i; + } + + if (slot1 != -1) + { + // sendModuleError("slot: " + slot + ", stack:" + stack.getName().getString()); + mc.interactionManager.clickSlot(0, slot1, 0, SlotActionType.PICKUP, mc.player); + mc.interactionManager.clickSlot(0, slot + 36, 0, SlotActionType.PICKUP, mc.player); + if (!mc.player.currentScreenHandler.getCursorStack().isEmpty()) + { + mc.interactionManager.clickSlot(0, slot1, 0, SlotActionType.PICKUP, mc.player); + } + } + } + + public boolean isSame(ItemStack stack1, ItemStack stack2, boolean outOfObsidian) + { + if (resistantConfig.get() && stack1.getItem() == Items.OBSIDIAN && outOfObsidian) + { + return stack2.getItem() == Items.ENDER_CHEST || stack2.getItem() == Items.CRYING_OBSIDIAN; + } + + else if (stack1.getItem() instanceof BlockItem blockItem + && (!(stack2.getItem() instanceof BlockItem blockItem1) || blockItem.getBlock() != blockItem1.getBlock())) + { + return false; + } + + else if (!stack1.getName().getString().equals(stack2.getName().getString())) + { + return false; + } + + return stack1.getItem().equals(stack2.getItem()); + } + +} diff --git a/src/main/java/com/genyo/addon/modules/combat/KFCSpawnKill.java b/src/main/java/com/genyo/addon/modules/combat/KFCSpawnKill.java new file mode 100644 index 0000000..ce3a2df --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/combat/KFCSpawnKill.java @@ -0,0 +1,972 @@ +package com.genyo.addon.modules.combat; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.network.DisconnectEvent; +import com.genyo.addon.events.network.PlayerTickEvent; +import com.genyo.addon.events.render.RenderWorldEvent; +import com.genyo.addon.events.world.RemoveEntityEvent; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.managers.world.tick.TickSync; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.modules.world.GenyoAutoMine; +import com.genyo.addon.render.RenderBuffers; +import com.genyo.addon.settings.FloatSetting; +import com.genyo.addon.utils.entity.EntityUtil; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import com.genyo.addon.utils.player.EnchantmentUtil; +import com.genyo.addon.utils.player.PlayerUtil; +import com.genyo.addon.utils.player.RotationUtil; +import com.genyo.addon.utils.render.SInterpolation; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.friends.Friends; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.AttributeModifiersComponent; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.entity.decoration.EndCrystalEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.projectile.ArrowEntity; +import net.minecraft.entity.projectile.thrown.ExperienceBottleEntity; +import net.minecraft.item.*; +import net.minecraft.network.packet.c2s.play.*; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; +import org.apache.commons.lang3.mutable.MutableDouble; + +import java.util.Comparator; +import java.util.stream.Stream; + +public class KFCSpawnKill extends GenyoModule { + + public KFCSpawnKill() { + super(GenyoAddon.GENYO, "KFC Spawn Kill", "ask about the name, i won't tell you."); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgRotate = settings.createGroup("Rotate"); + private final SettingGroup sgTarget = settings.createGroup("Target"); + private final SettingGroup sgRender = settings.createGroup("Render"); + + private final Setting multitaskConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Multitask") + .description("tesco") + .defaultValue(false) + .build() + ); + + private final Setting swingConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Swing") + .description("Swings the hand after attacking") + .defaultValue(true) + .build() + ); + + private final Setting modeConfig = sgGeneral.add(new EnumSetting.Builder() + .name("Mode") + .description("The mode for targeting entities to attack") + .defaultValue(TargetMode.SWITCH) + .build() + ); + + private final Setting priorityConfig = sgGeneral.add(new EnumSetting.Builder() + .name("Priority") + .description("The value to prioritize when searching for targets") + .defaultValue(Priority.HEALTH) + .build() + ); + + private final Setting searchRangeConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Enemy Range") + .description("Range to search for targets") + .min(1.0f) + .defaultValue(5.0f) + .max(10.0f) + .build() + ); + + private final Setting rangeConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Range") + .description("Range to attack entities") + .min(1.0f) + .defaultValue(4.5f) + .max(6.0f) + .build() + ); + + private final Setting wallRangeConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Wall Range") + .description("Range to attack entities through walls") + .min(1.0f) + .defaultValue(4.5f) + .max(6.0f) + .build() + ); + + private final Setting vanillaRangeConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Vanilla Range") + .description("Only attack within vanilla range") + .defaultValue(false) + .build() + ); + + private final Setting fovConfig = sgGeneral.add(new FloatSetting.Builder() + .name("FOV") + .description("Field of view to attack entities") + .min(1.0f) + .defaultValue(180.0f) + .max(180.0f) + .build() + ); + + private final Setting attackDelayConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Attack Delay") + .description("Delays attacks according to minecraft hit delays for maximum damage per attack") + .defaultValue(true) + .build() + ); + + private final Setting attackSpeedConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Attack Speed") + .description("Delay for attacks (Only functions if AttackDelay is off)") + .min(1.0f) + .defaultValue(20.0f) + .max(20.0f) + .visible(() -> !attackDelayConfig.get()) + .build() + ); + + private final Setting randomSpeedConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Random Speed") + .description("Randomized delay for attacks (Only functions if AttackDelay is off)") + .min(0.0f) + .defaultValue(0.0f) + .max(10.0f) + .visible(() -> !attackDelayConfig.get()) + .build() + ); + + private final Setting swapDelayConfig = sgGeneral.add(new FloatSetting.Builder() + .name("Swap Penalty") + .description("Delay for attacking after swapping items which prevents NCP flags") + .min(0.0f) + .defaultValue(0.0f) + .max(10.0f) + .build() + ); + + private final Setting tpsSyncConfig = sgGeneral.add(new EnumSetting.Builder() + .name("TPS Sync") + .description("Syncs the attacks with the server TPS") + .defaultValue(TickSync.NONE) + .build() + ); + + private final Setting autoSwapConfig = sgGeneral.add(new EnumSetting.Builder() + .name("Auto Swap") + .description("Automatically swaps to a weapon before attacking") + .defaultValue(Swap.OFF) + .build() + ); + + private final Setting swordCheckConfig = sgGeneral.add(new BoolSetting.Builder() + .name("Sword-Check") + .description("Checks if a weapon is in the hand before attacking") + .defaultValue(true) + .build() + ); + + // Rotate + + private final Setting hitVectorConfig = sgRotate.add(new EnumSetting.Builder() + .name("Hit Vector") + .description("The vector to aim for when attacking entities") + .defaultValue(Vector.FEET) + .build() + ); + + private final Setting rotateConfig = sgRotate.add(new BoolSetting.Builder() + .name("Rotate") + .description("Rotate before attacking") + .defaultValue(false) + .build() + ); + + private final Setting silentRotateConfig = sgRotate.add(new BoolSetting.Builder() + .name("Rotate Silent") + .description("Rotates silently to server") + .defaultValue(false) + .visible(rotateConfig::get) + .build() + ); + + private final Setting strictRotateConfig = sgRotate.add(new BoolSetting.Builder() + .name("Yaw Step") + .description("Rotates yaw over multiple ticks to prevent certain rotation flags in NCP") + .defaultValue(false) + .visible(rotateConfig::get) + .build() + ); + + private final Setting rotateLimitConfig = sgRotate.add(new IntSetting.Builder() + .name("YawStep-Limit") + .description("Maximum yaw rotation in degrees for one tick") + .min(1) + .defaultValue(180) + .max(180) + .build() + ); + + private final Setting ticksExistedConfig = sgRotate.add(new IntSetting.Builder() + .name("Ticks Existed") + .description("The minimum age of the entity to be considered for attack") + .min(0) + .defaultValue(0) + .max(200) + .build() + ); + + private final Setting armorCheckConfig = sgRotate.add(new BoolSetting.Builder() + .name("Armor Check") + .description("Checks if target has armor before attacking") + .defaultValue(false) + .build() + ); + + private final Setting stopSprintConfig = sgRotate.add(new BoolSetting.Builder() + .name("Stop Sprint") + .description("Stops sprinting before attacking to maintain vanilla behavior") + .defaultValue(false) + .build() + ); + + private final Setting stopShieldConfig = sgRotate.add(new BoolSetting.Builder() + .name("Stop Shield") + .description("Automatically handles shielding before attacking") + .defaultValue(false) + .build() + ); + + private final Setting maceBreachConfig = sgRotate.add(new BoolSetting.Builder() + .name("Mace Breach") + .description("Abuses vanilla exploit to apply breach enchantment to swords") + .defaultValue(false) + .visible(() -> autoSwapConfig.get() != Swap.SILENT) + .build() + ); + + // Target + + private final Setting playersConfig = sgTarget.add(new BoolSetting.Builder() + .name("Players") + .description("Target players") + .defaultValue(true) + .build() + ); + + private final Setting monstersConfig = sgTarget.add(new BoolSetting.Builder() + .name("Monsters") + .description("Target monsters") + .defaultValue(false) + .build() + ); + + private final Setting neutralsConfig = sgTarget.add(new BoolSetting.Builder() + .name("Neutrals") + .description("Target neutrals") + .defaultValue(false) + .build() + ); + + + private final Setting animalsConfig = sgTarget.add(new BoolSetting.Builder() + .name("Animals") + .description("Target animals") + .defaultValue(false) + .build() + ); + + private final Setting invisiblesConfig = sgTarget.add(new BoolSetting.Builder() + .name("Invisibles") + .description("Target invisible entities") + .defaultValue(true) + .build() + ); + + // Render + + private final Setting renderConfig = sgRender.add(new BoolSetting.Builder() + .name("Render") + .description("Renders an indicator over the target") + .defaultValue(true) + .build() + ); + + private final Setting disableDeathConfig = sgRender.add(new BoolSetting.Builder() + .name("Disable on Death") + .description("Disables during disconnect/death") + .defaultValue(false) + .build() + ); + + private final Setting color = sgRender.add(new ColorSetting.Builder() + .name("Render Color") + .description("asdsadsadsadsadsa") + .defaultValue(new Color(236, 243, 122, 255)) + .build() + ); + + private Entity entityTarget; + private long randomDelay = -1; + + private boolean shielding; + private boolean sneaking; + private boolean sprinting; + + private long lastAttackTime; + private final Timer critTimer = new CacheTimer(); + private final Timer autoSwapTimer = new CacheTimer(); + private final Timer switchTimer = new CacheTimer(); + private boolean rotated; + + private float[] silentRotations; + + @Override + public void onDeactivate() { + entityTarget = null; + silentRotations = null; + } + + @EventHandler + public void onDisconnect(DisconnectEvent event) + { + if (disableDeathConfig.get()) { + sendDisableMsg("Disabled because Auto Disable."); + toggle(); + } + } + + @EventHandler + public void onRemoveEntity(RemoveEntityEvent event) + { + if (disableDeathConfig.get() && event.entity == mc.player) { + sendDisableMsg("Disabled because Auto Disable."); + toggle(); + } + } + + @EventHandler + public void onPlayerUpdate(PlayerTickEvent event) + { + if (Modules.get().get(GenyoAutoCrystal.class).isAttacking() + || Modules.get().get(GenyoAutoCrystal.class).isPlacing() + || autoSwapConfig.get() == Swap.SILENT && Modules.get().get(GenyoAutoMine.class).isSilentSwapping() + || mc.player.isSpectator()) + { + return; + } + + if (!multitaskConfig.get() && checkMultitask(true)) return; + + final Vec3d eyepos = Managers.POSITION.getEyePos(); + entityTarget = switch (modeConfig.get()) + { + case SWITCH -> getAttackTarget(eyepos); + case SINGLE -> + { + if (entityTarget == null || !entityTarget.isAlive() + || !isInAttackRange(eyepos, entityTarget)) + { + yield getAttackTarget(eyepos); + } + yield entityTarget; + } + }; + if (entityTarget == null || !switchTimer.passed(swapDelayConfig.get() * 25.0f)) + { + silentRotations = null; + return; + } + if (mc.player.isUsingItem() && mc.player.getActiveHand() == Hand.MAIN_HAND + || mc.options.attackKey.isPressed() || PlayerUtil.isHotbarKeysPressed()) + { + autoSwapTimer.reset(); + } + + int slot = getSwordSlot(); + // END PRE + boolean silentSwapped = false; + if (!(mc.player.getMainHandStack().getItem() instanceof SwordItem) && slot != -1) + { + switch (autoSwapConfig.get()) + { + case NORMAL -> + { + if (autoSwapTimer.passed(500)) + { + Managers.INVENTORY.setClientSlot(slot); + } + } + case SILENT -> + { + Managers.INVENTORY.setSlot(slot); + silentSwapped = true; + } + } + } + if (!isHoldingSword() && autoSwapConfig.get() != Swap.SILENT) + { + return; + } + if (rotateConfig.get()) + { + float[] rotation = RotationUtil.getRotationsTo(mc.player.getEyePos(), + getAttackRotateVec(entityTarget)); + if (!silentRotateConfig.get() && strictRotateConfig.get()) + { + float serverYaw = Managers.ROTATION.getWrappedYaw(); + float diff = serverYaw - rotation[0]; + float diff1 = Math.abs(diff); + if (diff1 > 180.0f) + { + diff += diff > 0.0f ? -360.0f : 360.0f; + } + int dir = diff > 0.0f ? -1 : 1; + float deltaYaw = dir * rotateLimitConfig.get(); + float yaw; + if (diff1 > rotateLimitConfig.get()) + { + yaw = serverYaw + deltaYaw; + rotated = false; + } + else + { + yaw = rotation[0]; + rotated = true; + } + rotation[0] = yaw; + } + else + { + rotated = true; + } + // what what you cannot hop in my car + // bentley coupe ridin with stars + if (silentRotateConfig.get()) + { + silentRotations = rotation; + } + else + { + setRotation(rotation[0], rotation[1]); + } + } + if (isRotationBlocked() || !rotated && rotateConfig.get() || !isInAttackRange(eyepos, entityTarget)) + { + Managers.INVENTORY.syncToClient(); + return; + } + if (attackDelayConfig.get()) + { + PlayerInventory inventory = mc.player.getInventory(); + ItemStack itemStack = inventory.getStack((slot == -1 || !swordCheckConfig.get()) ? mc.player.getInventory().selectedSlot : slot); + + MutableDouble attackSpeed = new MutableDouble( + mc.player.getAttributeBaseValue(EntityAttributes.ATTACK_SPEED)); + + AttributeModifiersComponent attributeModifiers = + itemStack.get(DataComponentTypes.ATTRIBUTE_MODIFIERS); + if (attributeModifiers != null) + { + attributeModifiers.applyModifiers(EquipmentSlot.MAINHAND, (entry, modifier) -> + { + if (entry == EntityAttributes.ATTACK_SPEED) + { + attackSpeed.add(modifier.value()); + } + }); + } + + double attackCooldownTicks = 1.0 / attackSpeed.getValue() * 20.0; + + int breachSlot = getBreachMaceSlot(); + if (autoSwapConfig.get() != Swap.SILENT && maceBreachConfig.get() && breachSlot != -1) + { + Managers.INVENTORY.setSlot(breachSlot); + } + + float ticks = 20.0f - Managers.TICK.getTickSync(tpsSyncConfig.get()); + float currentTime = (System.currentTimeMillis() - lastAttackTime) + (ticks * 50.0f); + if ((currentTime / 50.0f) >= attackCooldownTicks && attackTarget(entityTarget)) + { + lastAttackTime = System.currentTimeMillis(); + } + + if (autoSwapConfig.get() != Swap.SILENT && maceBreachConfig.get() && breachSlot != -1) + { + Managers.INVENTORY.syncToClient(); + } + } + else + { + if (randomDelay < 0) + { + randomDelay = (long) RANDOM.nextFloat((randomSpeedConfig.get() * 10.0f) + 1.0f); + } + float delay = (attackSpeedConfig.get() * 50.0f) + randomDelay; + + int breachSlot = getBreachMaceSlot(); + if (autoSwapConfig.get() != Swap.SILENT && maceBreachConfig.get() && breachSlot != -1) + { + Managers.INVENTORY.setSlot(breachSlot); + } + + long currentTime = System.currentTimeMillis() - lastAttackTime; + if (currentTime >= 1000.0f - delay && attackTarget(entityTarget)) + { + randomDelay = -1; + lastAttackTime = System.currentTimeMillis(); + } + + if (autoSwapConfig.get() != Swap.SILENT && maceBreachConfig.get() && breachSlot != -1) + { + Managers.INVENTORY.syncToClient(); + } + } + + if (autoSwapConfig.get() == Swap.SILENT && silentSwapped) + { + Managers.INVENTORY.syncToClient(); + } + } + + @EventHandler + public void onPacketSend(PacketEvent.Send event) { + if (mc.player == null) return; + + if (event.packet instanceof UpdateSelectedSlotC2SPacket) { + switchTimer.reset(); + } + } + + @EventHandler + public void onRender3D(Render3DEvent event) { + if (Modules.get().get(GenyoAutoCrystal.class).isAttacking() + || Modules.get().get(GenyoAutoCrystal.class).isPlacing() || mc.player.isSpectator()) + { + return; + } + + if (entityTarget != null && renderConfig.get() && (isHoldingSword() || autoSwapConfig.get() == Swap.SILENT)) + { + long currentTime = System.currentTimeMillis() - lastAttackTime; + float animFactor = 1.0f - MathHelper.clamp(currentTime / 1000f, 0.0f, 1.0f); + int attackDelay = (int) (70.0 * animFactor); + + event.renderer.box(SInterpolation.getInterpolatedEntityBox(entityTarget), color.get().a(30 + attackDelay), + color.get().a(100), ShapeMode.Both, 0); + } + } + + private boolean attackTarget(Entity entity) + { +/* + Entity castEntity; + // validate our server-sided rotations + if (mc.crosshairTarget == null || mc.crosshairTarget.getType() != HitResult.Type.ENTITY) { + return false; + } + // Get the entity raycasted & then check. If invalid, fail + castEntity = ((EntityHitResult) mc.crosshairTarget).getEntity(); + if (castEntity == null || !castEntity.isAttackable()) { + return false; + } + preAttackTarget(); + mc.doAttack(); + postAttackTarget(castEntity); +*/ + preAttackTarget(); + + if (silentRotateConfig.get() && silentRotations != null) + { + setRotationSilent(silentRotations[0], silentRotations[1]); + } + + PlayerInteractEntityC2SPacket packet = PlayerInteractEntityC2SPacket.attack(entity, mc.player.isSneaking()); + Managers.NETWORK.sendPacket(packet); + if (swingConfig.get()) + { + mc.player.swingHand(Hand.MAIN_HAND); + } + else + { + Managers.NETWORK.sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + } + postAttackTarget(entity); + + if (silentRotateConfig.get()) + { + Managers.ROTATION.setRotationSilentSync(); + } + return true; + } + + private int getSwordSlot() + { + float sharp = 0.0f; + int slot = -1; + // Maximize item attack damage + for (int i = 0; i < 9; i++) + { + final ItemStack stack = mc.player.getInventory().getStack(i); + if (stack.getItem() instanceof SwordItem swordItem) + { + float sharpness = EnchantmentUtil.getLevel(stack, + Enchantments.SHARPNESS) * 0.5f + 0.5f; + float dmg = swordItem.getDefaultStack().getDamage() + sharpness; + if (dmg > sharp) + { + sharp = dmg; + slot = i; + } + } + else if (stack.getItem() instanceof AxeItem axeItem) + { + float sharpness = EnchantmentUtil.getLevel(stack, + Enchantments.SHARPNESS) * 0.5f + 0.5f; + float dmg = axeItem.getDefaultStack().getDamage() + sharpness; + if (dmg > sharp) + { + sharp = dmg; + slot = i; + } + } + else if (stack.getItem() instanceof TridentItem) + { + float sharpness = EnchantmentUtil.getLevel(stack, + Enchantments.SHARPNESS) * 0.5f + 0.5f; + float dmg = TridentItem.ATTACK_DAMAGE + sharpness; + if (dmg > sharp) + { + sharp = dmg; + slot = i; + } + } + else if (stack.getItem() instanceof MaceItem) + { + float sharpness = EnchantmentUtil.getLevel(stack, + Enchantments.SHARPNESS) * 0.5f + 0.5f; + float dmg = 5.0f + sharpness; + if (dmg > sharp) + { + sharp = dmg; + slot = i; + } + } + } + return slot; + } + + private int getBreachMaceSlot() + { + int slot = -1; + int maxBreach = 0; + for (int i = 0; i < 9; i++) + { + ItemStack stack = mc.player.getInventory().getStack(i); + if (!(stack.getItem() instanceof MaceItem)) + { + continue; + } + int breach = EnchantmentUtil.getLevel(stack, Enchantments.BREACH); + if (breach > maxBreach) + { + slot = i; + maxBreach = breach; + } + } + return slot; + } + + private void preAttackTarget() + { + final ItemStack offhand = mc.player.getOffHandStack(); + // Shield state + shielding = false; + if (stopShieldConfig.get()) + { + shielding = offhand.getItem() == Items.SHIELD && mc.player.isBlocking(); + if (shielding) + { + Managers.NETWORK.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.RELEASE_USE_ITEM, + Managers.POSITION.getBlockPos(), Direction.getFacing(mc.player.getX(), + mc.player.getY(), mc.player.getZ()))); + } + } + sneaking = false; + sprinting = false; + if (stopSprintConfig.get()) + { + sneaking = Managers.POSITION.isSneaking(); + if (sneaking) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, + ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY)); + } + sprinting = Managers.POSITION.isSprinting(); + if (sprinting) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, + ClientCommandC2SPacket.Mode.STOP_SPRINTING)); + } + } + } + + // RELEASE + private void postAttackTarget(Entity entity) + { + if (shielding) + { + Managers.NETWORK.sendSequencedPacket(s -> + new PlayerInteractItemC2SPacket(Hand.OFF_HAND, s, mc.player.getYaw(), mc.player.getPitch())); + } + if (sneaking) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, + ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY)); + } + if (sprinting) + { + Managers.NETWORK.sendPacket(new ClientCommandC2SPacket(mc.player, + ClientCommandC2SPacket.Mode.START_SPRINTING)); + } +// if (CriticalsModule.getInstance().isEnabled() && critTimer.passed(500)) { +// if (!mc.player.isOnGround() +// || mc.player.isRiding() +// || mc.player.isSubmergedInWater() +// || mc.player.isInLava() +// || mc.player.isHoldingOntoLadder() +// || mc.player.hasStatusEffect(StatusEffects.BLINDNESS) +// || mc.player.input.jumping) { +// return; +// } +// CriticalsModule.getInstance().preAttackPacket(entity); +// critTimer.reset(); +// } + } + + private Entity getAttackTarget(Vec3d pos) + { + double min = Double.MAX_VALUE; + Entity attackTarget = null; + for (Entity entity : mc.world.getEntities()) { + if (entity == null || entity == mc.player + || !entity.isAlive() || !isEnemy(entity) + || (entity instanceof PlayerEntity && Friends.get().isFriend((PlayerEntity) entity)) + || entity instanceof EndCrystalEntity + || entity instanceof ItemEntity + || entity instanceof ArrowEntity + || entity instanceof ExperienceBottleEntity) + { + continue; + } + if (armorCheckConfig.get() + && entity instanceof LivingEntity livingEntity + && !livingEntity.getArmorItems().iterator().hasNext()) + { + continue; + } + double dist = pos.distanceTo(entity.getPos()); + if (dist <= searchRangeConfig.get()) + { + if (entity.age < ticksExistedConfig.get()) + { + continue; + } + switch (priorityConfig.get()) + { + case DISTANCE -> + { + if (dist < min) + { + min = dist; + attackTarget = entity; + } + } + case HEALTH -> + { + if (entity instanceof LivingEntity e) + { + float health = e.getHealth() + e.getAbsorptionAmount(); + if (health < min) + { + min = health; + attackTarget = entity; + } + } + } + case ARMOR -> + { + if (entity instanceof LivingEntity e) + { + float armor = getArmorDurability(e); + if (armor < min) + { + min = armor; + attackTarget = entity; + } + } + } + } + } + } + return attackTarget; + } + + private float getArmorDurability(LivingEntity e) + { + float edmg = 0.0f; + float emax = 0.0f; + for (ItemStack armor : e.getArmorItems()) + { + if (armor != null && !armor.isEmpty()) + { + edmg += armor.getDamage(); + emax += armor.getMaxDamage(); + } + } + return 100.0f - edmg / emax; + } + + public boolean isInAttackRange(Vec3d pos, Entity entity) + { + final Vec3d entityPos = getAttackRotateVec(entity); + double dist = pos.distanceTo(entityPos); + return isInAttackRange(dist, pos, entityPos); + } + + /** + * @param dist + * @param pos + * @return + */ + public boolean isInAttackRange(double dist, Vec3d pos, Vec3d entityPos) + { + if (vanillaRangeConfig.get() && dist > 3.0f) + { + return false; + } + if (dist > rangeConfig.get()) + { + return false; + } + BlockHitResult result = mc.world.raycast(new RaycastContext( + pos, entityPos, + RaycastContext.ShapeType.COLLIDER, + RaycastContext.FluidHandling.NONE, mc.player)); + if (result != null && !result.getBlockPos().equals(BlockPos.ofFloored(entityPos)) && dist > wallRangeConfig.get()) + { + return false; + } + if (fovConfig.get() != 180.0f) + { + float[] rots = RotationUtil.getRotationsTo(pos, entityPos); + float diff = MathHelper.wrapDegrees(mc.player.getYaw()) - rots[0]; + float magnitude = Math.abs(diff); + return magnitude <= fovConfig.get(); + } + return true; + } + + public boolean isHoldingSword() + { + return !swordCheckConfig.get() || mc.player.getMainHandStack().getItem() instanceof SwordItem + || mc.player.getMainHandStack().getItem() instanceof AxeItem + || mc.player.getMainHandStack().getItem() instanceof TridentItem + || mc.player.getMainHandStack().getItem() instanceof MaceItem; + } + + private Vec3d getAttackRotateVec(Entity entity) + { + Vec3d feetPos = entity.getPos(); + return switch (hitVectorConfig.get()) + { + case FEET -> feetPos; + case TORSO -> feetPos.add(0.0, entity.getHeight() / 2.0f, 0.0); + case EYES -> entity.getEyePos(); + case AUTO -> + { + Vec3d torsoPos = feetPos.add(0.0, entity.getHeight() / 2.0f, 0.0); + Vec3d eyesPos = entity.getEyePos(); + yield Stream.of(feetPos, torsoPos, eyesPos).min(Comparator.comparing(b -> mc.player.getEyePos().squaredDistanceTo(b))).orElse(eyesPos); + } + }; + } + + /** + * Returns true if the {@link Entity} is a valid enemy to attack. + * + * @param e The potential enemy entity + * @return true if the entity is an enemy + * @see EntityUtil + */ + private boolean isEnemy(Entity e) + { + return (!e.isInvisible() || invisiblesConfig.get()) + && e instanceof PlayerEntity && playersConfig.get() + || EntityUtil.isMonster(e) && monstersConfig.get() + || EntityUtil.isNeutral(e) && neutralsConfig.get() + || EntityUtil.isPassive(e) && animalsConfig.get(); + } + + public Entity getEntityTarget() + { + return entityTarget; + } + + public enum TargetMode + { + SWITCH, + SINGLE + } + + public enum Swap + { + NORMAL, + SILENT, + OFF + } + + public enum Vector + { + EYES, + TORSO, + FEET, + AUTO + } + + public enum Priority + { + HEALTH, + DISTANCE, + ARMOR + } + +} diff --git a/src/main/java/com/genyo/addon/modules/misc/CombatBrainrot.java b/src/main/java/com/genyo/addon/modules/misc/CombatBrainrot.java new file mode 100644 index 0000000..261ddd6 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/misc/CombatBrainrot.java @@ -0,0 +1,89 @@ +package com.genyo.addon.modules.misc; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.modules.GenyoModule; +import com.genyo.addon.settings.FloatSetting; +import com.genyo.addon.utils.math.MathUtil; +import com.genyo.addon.utils.math.timer.CacheTimer; +import com.genyo.addon.utils.math.timer.Timer; +import meteordevelopment.meteorclient.events.entity.player.AttackEntityEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.settings.StringListSetting; +import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.decoration.EndCrystalEntity; + +import java.util.ArrayList; +import java.util.List; + +public class CombatBrainrot extends GenyoModule { + + public CombatBrainrot() { + super(GenyoAddon.GENYO, "combat-brainrot", "says something sigma when punching a crystal."); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting> brainrots = sgGeneral.add(new StringListSetting.Builder() + .name("The") + .description("ewfsdfdsfesfewfwerewrewrwerewrewrew") + .defaultValue(List.of("hfgjksdhfhdskjfhdsfsd", "Niger biger", "asdadsadsadasdasdasdasdsadsada", "brain damge")) + .build() + ); + + private final Setting delay = sgGeneral.add(new FloatSetting.Builder() + .name("Delay") + .description("to maybe not get kicked or smth idk (in milliseconds)") + .min(0.1f) + .defaultValue(0.2f) + .max(1f) + .build() + ); + + //TODO: whisper + private final Timer timer = new CacheTimer(); + private final List queue = new ArrayList<>(); + + @Override + public void onActivate() { + timer.reset(); + queue.clear(); + + if (brainrots.get().isEmpty()) { + toggle(); + sendDisableMsg("No brainrots available."); + } + } + + @Override + public void onDeactivate() { + timer.reset(); + queue.clear(); + } + + @EventHandler + public void onTick(TickEvent.Pre event) { + if (mc.player == null || mc.world == null) return; + if (queue.isEmpty()) return; + + if (timer.passed(delay.get() * 1000)) { + String message = queue.getFirst(); + + ChatUtils.sendPlayerMsg(message); + queue.removeFirst(); + timer.reset(); + } + } + + @EventHandler + public void onAttackEntity(AttackEntityEvent event) { + if (mc.player == null || mc.world == null) return; + + if (!(event.entity instanceof EndCrystalEntity)) return; + + queue.add(brainrots.get().get(MathUtil.pickRandom(brainrots.get()))); + } + +} diff --git a/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java b/src/main/java/com/genyo/addon/modules/misc/GenyoAutoEZ.java similarity index 95% rename from src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java rename to src/main/java/com/genyo/addon/modules/misc/GenyoAutoEZ.java index 832adba..fa2f52e 100644 --- a/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java +++ b/src/main/java/com/genyo/addon/modules/misc/GenyoAutoEZ.java @@ -1,9 +1,10 @@ -package com.genyo.addon.modules; +package com.genyo.addon.modules.misc; import com.genyo.addon.GenyoAddon; +import com.genyo.addon.modules.GenyoModule; import com.genyo.addon.systems.incombat.CombatPerson; import com.genyo.addon.systems.incombat.InCombatSystem; -import com.genyo.addon.utils.MathUtil; +import com.genyo.addon.utils.math.MathUtil; import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.*; @@ -40,7 +41,7 @@ public GenyoAutoEZ() { .description("How many ticks to wait between sending messages.") .defaultValue(10) .min(0) - .sliderRange(0, 100) + .max(100) .build() ); @@ -94,6 +95,9 @@ public GenyoAutoEZ() { private final HashMap taggedPlayers = new HashMap<>(); private int timer = 0; + @Override + public void onDeactivate() { taggedPlayers.clear(); } + @Override public void onActivate() { taggedPlayers.clear(); @@ -102,7 +106,8 @@ public void onActivate() { @EventHandler(priority = EventPriority.HIGHEST) private void onTick(TickEvent.Pre event) { if (mc.player == null && mc.world == null) return; - timer++; + + if (!messageQueue.isEmpty()) timer++; if (timer >= tickDelay.get() && !messageQueue.isEmpty()) { Message msg = messageQueue.get(0); @@ -158,16 +163,9 @@ private void onReceive(PacketEvent.Receive event) { } private boolean checkPersonValidity(PlayerEntity player) { - if (InCombatSystem.get().isEnabled() && combatFocus.get()) - if (!InCombatSystem.get().contains(player)) return false; // kell? - - if (taggedPlayers.containsKey(player)) { - return true; - } + return taggedPlayers.containsKey(player); //TODO: if we want to display this for everyone - - return false; } diff --git a/src/main/java/com/genyo/addon/modules/misc/GenyoDiscord.java b/src/main/java/com/genyo/addon/modules/misc/GenyoDiscord.java new file mode 100644 index 0000000..91619d6 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/misc/GenyoDiscord.java @@ -0,0 +1,321 @@ +package com.genyo.addon.modules.misc; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.modules.GenyoModule; +import meteordevelopment.discordipc.DiscordIPC; +import meteordevelopment.discordipc.RichPresence; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.events.game.OpenScreenEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.WidgetScreen; +import meteordevelopment.meteorclient.gui.utils.StarscriptTextBoxRenderer; +import meteordevelopment.meteorclient.gui.widgets.WWidget; +import meteordevelopment.meteorclient.gui.widgets.pressable.WButton; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.misc.DiscordPresence; +import meteordevelopment.meteorclient.utils.Utils; +import meteordevelopment.meteorclient.utils.misc.MeteorStarscript; +import meteordevelopment.orbit.EventHandler; +import meteordevelopment.starscript.Script; +import net.minecraft.client.gui.screen.*; +import net.minecraft.client.gui.screen.multiplayer.AddServerScreen; +import net.minecraft.client.gui.screen.multiplayer.ConnectScreen; +import net.minecraft.client.gui.screen.multiplayer.DirectConnectScreen; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; +import net.minecraft.client.gui.screen.option.*; +import net.minecraft.client.gui.screen.pack.PackScreen; +import net.minecraft.client.gui.screen.world.*; +import net.minecraft.client.realms.gui.screen.RealmsScreen; +import net.minecraft.util.Pair; +import net.minecraft.util.Util; + +import java.util.ArrayList; +import java.util.List; + +public class GenyoDiscord extends GenyoModule { + + public enum SelectMode { + Random, + Sequential + } + + private final SettingGroup sgLine1 = settings.createGroup("Line 1"); + private final SettingGroup sgLine2 = settings.createGroup("Line 2"); + + // Line 1 + + private final Setting> line1Strings = sgLine1.add(new StringListSetting.Builder() + .name("line-1-messages") + .description("Messages used for the first line.") + .defaultValue("{player}", "{server}", "asdasdsadasdsadasdsa", "I have brain damge") + .onChanged(strings -> recompileLine1()) + .renderer(StarscriptTextBoxRenderer.class) + .build() + ); + + private final Setting line1UpdateDelay = sgLine1.add(new IntSetting.Builder() + .name("line-1-update-delay") + .description("How fast to update the first line in ticks.") + .defaultValue(200) + .min(10) + .sliderRange(10, 200) + .build() + ); + + private final Setting line1SelectMode = sgLine1.add(new EnumSetting.Builder() + .name("line-1-select-mode") + .description("How to select messages for the first line.") + .defaultValue(SelectMode.Sequential) + .build() + ); + + // Line 2 + + private final Setting> line2Strings = sgLine2.add(new StringListSetting.Builder() + .name("line-2-messages") + .description("Messages used for the second line.") + .defaultValue("genyo!", "{round(server.tps, 1)} TPS", "genyoo", "{server.player_count} Players online") + .onChanged(strings -> recompileLine2()) + .renderer(StarscriptTextBoxRenderer.class) + .build() + ); + + private final Setting line2UpdateDelay = sgLine2.add(new IntSetting.Builder() + .name("line-2-update-delay") + .description("How fast to update the second line in ticks.") + .defaultValue(60) + .min(10) + .sliderRange(10, 200) + .build() + ); + + private final Setting line2SelectMode = sgLine2.add(new EnumSetting.Builder() + .name("line-2-select-mode") + .description("How to select messages for the second line.") + .defaultValue(SelectMode.Sequential) + .build() + ); + + private static final RichPresence rpc = new RichPresence(); + private SmallImage currentSmallImage; + private int ticks; + private boolean forceUpdate, lastWasInMainMenu; + + private final List