From 411c2a342ad11d288e8b9530969dcb012fe63c72 Mon Sep 17 00:00:00 2001 From: Tristan Date: Thu, 3 Jul 2025 19:54:12 -0400 Subject: [PATCH 1/3] feat(better scaffold) --- .../module/impl/movement/ScaffoldModule.java | 81 +++++++++++-------- .../thoq/module/impl/visual/DebugModule.java | 15 +++- .../thoq/utilities/player/MoveUtility.java | 20 +++++ 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java b/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java index c12126d..8b5b7a6 100644 --- a/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java +++ b/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java @@ -16,6 +16,7 @@ package dev.thoq.module.impl.movement; +import dev.thoq.RyeClient; import dev.thoq.config.setting.impl.BooleanSetting; import dev.thoq.config.setting.impl.ModeSetting; import dev.thoq.config.setting.impl.NumberSetting; @@ -37,7 +38,6 @@ 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; @@ -50,6 +50,7 @@ public class ScaffoldModule extends Module { private final BooleanSetting swing = new BooleanSetting("Swing", "Swing arm when placing blocks", true); private final BooleanSetting rotate = new BooleanSetting("Rotate", "Rotate towards block placement", true); private final BooleanSetting tower = new BooleanSetting("Tower", "Enable tower mode when jumping", true); + private final BooleanSetting keepY = new BooleanSetting("KeepY", "Keep same Y position when placing blocks", false); private final NumberSetting searchRange = new NumberSetting<>("Search Range", "Block search radius", 3, 1, 6); private final NumberSetting bruteForceRayCastIntensity = new NumberSetting<>("Brute Force Intensity", "Intensity of rotation calculation", 5, 1, 10); @@ -62,8 +63,8 @@ public class ScaffoldModule extends Module { private BlockCache blockCache, lastBlockCache; private int startSlot, slot, lastSlot; - private long lastPlaceTime = 0; private float yaw, pitch; + private double keepYLevel = -1; public ScaffoldModule() { super("Scaffold", "Automatically bridges for you", ModuleCategory.WORLD); @@ -76,7 +77,8 @@ public ScaffoldModule() { addSetting(switchItemMode); addSetting(swing); addSetting(swingMode.setVisibilityCondition(swing::getValue)); - addSetting(tower); + addSetting(keepY.setVisibilityCondition(() -> !tower.getValue())); + addSetting(tower.setVisibilityCondition(() -> !keepY.getValue())); addSetting(towerMode.setVisibilityCondition(tower::getValue)); addSetting(towerSpeed.setVisibilityCondition(() -> tower.getValue() && towerMode.getValue().equals("Vanilla"))); } @@ -90,6 +92,10 @@ protected void onEnable() { slot = lastSlot = -1; blockCache = lastBlockCache = null; + if(keepY.getValue()) { + keepYLevel = Math.floor(mc.player.getY()) - 1; + } + yaw = getYaw() + 180; pitch = 80; } @@ -105,33 +111,35 @@ protected void onDisable() { mc.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(startSlot)); } } + + keepYLevel = -1; } @SuppressWarnings("unused") private final IEventListener motionEvent = event -> { if(mc.player == null || mc.world == null) return; - slot = findBlockSlot(); - - if(sprint.getValue() && MoveUtility.isMoving()) { - mc.player.setSprinting(true); - MoveUtility.setSpeed(0.2873); - } else { - mc.player.setSprinting(false); - MoveUtility.setSpeed(0.2); - } - - if(slot != -1) { - if(switchItemMode.getValue().equals("Client") && mc.player.getInventory().getSelectedSlot() != slot) { - mc.player.getInventory().setSelectedSlot(slot); + if(event.isPre()) { + slot = findBlockSlot(); + + if(sprint.getValue() && MoveUtility.isMoving()) { + mc.player.setSprinting(true); + MoveUtility.setSpeed(MoveUtility.getVanillaPlayerSprintSpeed()); + } else { + mc.player.setSprinting(false); + MoveUtility.setSpeed(MoveUtility.getVanillaPlayerSpeed()); } - if(switchItemMode.getValue().equals("Server") && lastSlot != slot && mc.getNetworkHandler() != null) { - mc.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(slot)); - lastSlot = slot; + + if(slot != -1) { + if(switchItemMode.getValue().equals("Client") && mc.player.getInventory().getSelectedSlot() != slot) { + mc.player.getInventory().setSelectedSlot(slot); + } + if(switchItemMode.getValue().equals("Server") && lastSlot != slot && mc.getNetworkHandler() != null) { + mc.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(slot)); + lastSlot = slot; + } } - } - if(event.isPre()) { blockCache = getBlockCache(); if(blockCache != null) lastBlockCache = blockCache; @@ -150,19 +158,19 @@ protected void onDisable() { mc.player.setVelocity(mc.player.getVelocity().x * 0.91f, mc.player.getVelocity().y, mc.player.getVelocity().z * 0.91f); } - if(tower.getValue() && mc.options.jumpKey.isPressed() && blockCache != null) { + if(!keepY.getValue() && tower.getValue() && mc.options.jumpKey.isPressed() && blockCache != null) { handleTower(); } - } - if(event.isPost() && lastBlockCache != null && slot != -1) { - placeBlock(); + if(lastBlockCache != null && slot != -1) { + placeBlock(); + } } }; @SuppressWarnings("unused") private final IEventListener packetSendEvent = event -> { - if(event.getPacket() instanceof UpdateSelectedSlotC2SPacket packet) { + if(event.getPacket() instanceof UpdateSelectedSlotC2SPacket packet && event.isPre()) { if(switchItemMode.getValue().equals("Server")) { startSlot = packet.getSelectedSlot(); event.cancel(); @@ -251,11 +259,16 @@ private void updateRotations() { private float getDirectionYaw(Direction direction) { switch(direction) { - case NORTH: return 0; - case SOUTH: return 180; - case WEST: return 90; - case EAST: return 270; - default: return getYaw(); + case NORTH: + return 0; + case SOUTH: + return 180; + case WEST: + return 90; + case EAST: + return 270; + default: + return getYaw(); } } @@ -315,7 +328,9 @@ private void handleTower() { private BlockCache getBlockCache() { if(mc.player == null || mc.world == null) return null; - BlockPos belowBlockPos = BlockPos.ofFloored(mc.player.getPos().subtract(0, 1, 0)); + double targetY = keepY.getValue() ? keepYLevel : mc.player.getY() - 1; + BlockPos belowBlockPos = new BlockPos((int) Math.floor(mc.player.getX()), (int) Math.floor(targetY), (int) Math.floor(mc.player.getZ())); + if(!mc.world.getBlockState(belowBlockPos).isAir()) return null; for(int x = 0; x < searchRange.getValue(); x++) { @@ -386,4 +401,4 @@ public Direction getEnumFacing() { return enumFacing; } } -} +} \ No newline at end of file diff --git a/src/client/java/dev/thoq/module/impl/visual/DebugModule.java b/src/client/java/dev/thoq/module/impl/visual/DebugModule.java index 923677b..e7e40b4 100644 --- a/src/client/java/dev/thoq/module/impl/visual/DebugModule.java +++ b/src/client/java/dev/thoq/module/impl/visual/DebugModule.java @@ -19,6 +19,7 @@ import dev.thoq.RyeClient; import dev.thoq.config.setting.impl.BooleanSetting; import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; import dev.thoq.event.impl.PacketReceiveEvent; import dev.thoq.module.Module; import dev.thoq.module.ModuleCategory; @@ -27,21 +28,33 @@ @SuppressWarnings("FieldCanBeLocal") public class DebugModule extends Module { private final BooleanSetting packetLog = new BooleanSetting("Packets", "Log all packets to console, may lag game", false); + private final BooleanSetting motionLog = new BooleanSetting("Motion", "Log motion values to console, may lag game", false); public DebugModule() { super("Debug", "Shows debug info-only of intrest to developers", ModuleCategory.VISUAL); addSetting(packetLog); + addSetting(motionLog); - if(RyeClient.getType().equals("Development")) { + if(RyeClient.getType().equals("Development") || RyeClient.getType().equals("Beta")) { this.setEnabled(true); } } + @SuppressWarnings("unused") private final IEventListener packetEvent = event -> { boolean packetLogEnabled = ((BooleanSetting) getSetting("Packets")).getValue(); if(packetLogEnabled) ChatUtility.sendDebug(event.getPacket().toString()); }; + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(!motionLog.getValue() || mc.player == null) return; + + ChatUtility.sendDebug("X=" + mc.player.getVelocity().x); + ChatUtility.sendDebug("Y=" + mc.player.getVelocity().y); + ChatUtility.sendDebug("Z=" + mc.player.getVelocity().z); + }; } diff --git a/src/client/java/dev/thoq/utilities/player/MoveUtility.java b/src/client/java/dev/thoq/utilities/player/MoveUtility.java index a1da54a..f74b5dd 100644 --- a/src/client/java/dev/thoq/utilities/player/MoveUtility.java +++ b/src/client/java/dev/thoq/utilities/player/MoveUtility.java @@ -22,6 +22,8 @@ @SuppressWarnings("unused") public class MoveUtility { private static final double VANILLA_PLAYER_FALL_MOTION = -0.0784000015258789; + private static final double VANILLA_PLAYER_SPEED = 0.11681545167924458; + private static final double VANILLA_PLAYER_SPRINT_SPEED = 0.1523673105277881; /** * Sets the player's movement speed @@ -197,4 +199,22 @@ public static void setMotionZ(double z) { public static double getVanillaFallingSpeed() { return VANILLA_PLAYER_FALL_MOTION; } + + /** + * Retrieves the default movement speed value for a vanilla player. + * + * @return The standard speed value for vanilla player movement. + */ + public static double getVanillaPlayerSpeed() { + return VANILLA_PLAYER_SPEED; + } + + /** + * Retrieves the default sprinting speed value for a vanilla player. + * + * @return The standard sprint speed defined for vanilla player mechanics. + */ + public static double getVanillaPlayerSprintSpeed() { + return VANILLA_PLAYER_SPRINT_SPEED; + } } From 056e382a05a0e30d6cf2feb5540ea47da65ac187 Mon Sep 17 00:00:00 2001 From: Tristan Date: Thu, 3 Jul 2025 22:07:44 -0400 Subject: [PATCH 2/3] feat(fixed bugs): Fixed reach+swing dist in ka and removed random space in scaffold --- .../dev/thoq/module/impl/combat/killaura/KillauraModule.java | 4 ++-- .../java/dev/thoq/module/impl/movement/ScaffoldModule.java | 1 + .../dev/thoq/module/impl/utility/disabler/DisablerModule.java | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java b/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java index 0850bae..c939e48 100644 --- a/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java +++ b/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java @@ -56,8 +56,8 @@ public class KillauraModule extends Module { private final ModeSetting attackMode = new ModeSetting("AttackMode", "Attack mode", "Single", "Single", "Switch", "Multi"); private final ModeSetting targetMode = new ModeSetting("Target", "Target types", "Players", "Players", "Passive", "Hostile", "All"); - private final NumberSetting swingDistance = new NumberSetting<>("SwingDistance", "Distance to start swinging", 4.5, 3.0, 1000.0); - private final NumberSetting reach = new NumberSetting<>("Reach", "Distance to actually attack from", 4.0, 3.0, 1000.0); + private final NumberSetting swingDistance = new NumberSetting<>("SwingDistance", "Distance to start swinging", 4.5, 3.0, 6.0); + private final NumberSetting reach = new NumberSetting<>("Reach", "Distance to actually attack from", 3.0, 3.0, 6.0); private final NumberSetting cps = new NumberSetting<>("CPS", "Attacks per second", 12, 1, 20); private final BooleanSetting noHitDelay = new BooleanSetting("NoHitDelay", "Remove attack delay", false); private final BooleanSetting raycast = new BooleanSetting("Raycast", "Check line of sight to target", true); diff --git a/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java b/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java index 8b5b7a6..e43efc3 100644 --- a/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java +++ b/src/client/java/dev/thoq/module/impl/movement/ScaffoldModule.java @@ -134,6 +134,7 @@ protected void onDisable() { if(switchItemMode.getValue().equals("Client") && mc.player.getInventory().getSelectedSlot() != slot) { mc.player.getInventory().setSelectedSlot(slot); } + if(switchItemMode.getValue().equals("Server") && lastSlot != slot && mc.getNetworkHandler() != null) { mc.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(slot)); lastSlot = slot; diff --git a/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java b/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java index 297296c..8334846 100644 --- a/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java +++ b/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java @@ -41,7 +41,9 @@ public DisablerModule() { @SuppressWarnings("unused") private final IEventListener tickEvent = event -> { - if(disabler.getEnabledOptions().size() > 1) + if(disabler.getEnabledOptions().isEmpty()) + setPrefix("None"); + else if(disabler.getEnabledOptions().size() > 1) setPrefix("Multi"); else setPrefix(disabler.getEnabledOptions().getFirst()); From 3ce6287ab685725b5458e42c8bde3c8ed335c696 Mon Sep 17 00:00:00 2001 From: Tristan Date: Sat, 5 Jul 2025 02:26:04 -0400 Subject: [PATCH 3/3] feat(changed 34 files) --- src/client/java/dev/thoq/RyeClient.java | 22 +- .../dev/thoq/command/impl/VClipCommand.java | 66 +++ .../client/ui/WatermarkTitleScreenMixin.java | 28 +- .../java/dev/thoq/module/SubModule.java | 19 + .../impl/combat/killaura/KillauraModule.java | 24 + .../impl/movement/AntiGravityModule.java | 48 ++ .../module/impl/movement/TargetStrafe.java | 46 -- .../impl/movement/TargetStrafeModule.java | 247 ++++++++++ .../impl/movement/flight/FlightModule.java | 9 +- .../movement/flight/vanilla/NormalFlight.java | 2 +- .../movement/flight/verus/VerusGlideFly.java | 16 +- .../longjump/verus/VerusPacketLongjump.java | 4 +- .../impl/movement/speed/SpeedModule.java | 4 +- .../movement/speed/spartan/SpartanSpeed.java | 57 +++ .../impl/movement/speed/verus/VerusSpeed.java | 2 +- .../impl/utility/antivoid/AntiVoidModule.java | 41 ++ .../antivoid/position/PositionAntiVoid.java | 55 +++ .../impl/utility/disabler/DisablerModule.java | 50 +- .../disabler/cubecraft/CubecraftDisabler.java | 15 +- .../omnisprint/OmniSprintDisabler.java | 15 +- .../disabler/spartan/SpartanDisabler.java | 57 +++ .../module/impl/visual/ArraylistModule.java | 8 +- .../thoq/module/impl/visual/HUDModule.java | 455 +++++------------- .../clickgui/dropdown/DropDownClickGUI.java | 18 +- .../dev/thoq/utilities/misc/ChatUtility.java | 9 +- .../thoq/utilities/misc/DoubleBlockPos.java | 26 + .../dev/thoq/utilities/misc/RyeConstants.java | 2 +- .../thoq/utilities/player/MoveUtility.java | 19 + .../thoq/utilities/player/PlayerUtility.java | 32 +- .../thoq/utilities/render/RenderUtility.java | 122 ++++- .../utilities/render/TextRendererUtility.java | 47 ++ .../java/dev/thoq/utilities/render/Theme.java | 142 +----- .../thoq/utilities/render/ThemeUtility.java | 2 +- .../assets/rye/images/rye_logo_white.png | Bin 0 -> 50393 bytes 34 files changed, 1088 insertions(+), 621 deletions(-) create mode 100644 src/client/java/dev/thoq/command/impl/VClipCommand.java create mode 100644 src/client/java/dev/thoq/module/impl/movement/AntiGravityModule.java delete mode 100644 src/client/java/dev/thoq/module/impl/movement/TargetStrafe.java create mode 100644 src/client/java/dev/thoq/module/impl/movement/TargetStrafeModule.java create mode 100644 src/client/java/dev/thoq/module/impl/movement/speed/spartan/SpartanSpeed.java create mode 100644 src/client/java/dev/thoq/module/impl/utility/antivoid/AntiVoidModule.java create mode 100644 src/client/java/dev/thoq/module/impl/utility/antivoid/position/PositionAntiVoid.java create mode 100644 src/client/java/dev/thoq/module/impl/utility/disabler/spartan/SpartanDisabler.java create mode 100644 src/client/java/dev/thoq/utilities/misc/DoubleBlockPos.java create mode 100644 src/main/resources/assets/rye/images/rye_logo_white.png diff --git a/src/client/java/dev/thoq/RyeClient.java b/src/client/java/dev/thoq/RyeClient.java index 2d61527..d37fc51 100644 --- a/src/client/java/dev/thoq/RyeClient.java +++ b/src/client/java/dev/thoq/RyeClient.java @@ -18,43 +18,39 @@ import dev.thoq.command.CommandBuilder; import dev.thoq.command.CommandRepository; -import dev.thoq.command.impl.BindCommand; -import dev.thoq.command.impl.ConfigCommand; -import dev.thoq.command.impl.SettingsCommand; -import dev.thoq.command.impl.ToggleCommand; +import dev.thoq.command.impl.*; import dev.thoq.config.KeybindManager; import dev.thoq.event.EventBus; import dev.thoq.module.ModuleBuilder; import dev.thoq.module.ModuleRepository; import dev.thoq.module.impl.combat.AttackDelayModule; import dev.thoq.module.impl.combat.killaura.KillauraModule; -import dev.thoq.module.impl.movement.StrafeModule; -import dev.thoq.module.impl.movement.HighJumpModule; +import dev.thoq.module.impl.movement.*; +import dev.thoq.module.impl.utility.antivoid.AntiVoidModule; import dev.thoq.module.impl.utility.disabler.DisablerModule; import dev.thoq.module.impl.world.TickBaseModule; import dev.thoq.module.impl.movement.flight.FlightModule; import dev.thoq.module.impl.combat.VelocityModule; import dev.thoq.module.impl.movement.longjump.LongJumpModule; -import dev.thoq.module.impl.movement.ScaffoldModule; import dev.thoq.module.impl.movement.speed.SpeedModule; import dev.thoq.module.impl.world.NukerModule; import dev.thoq.module.impl.combat.ReachModule; import dev.thoq.module.impl.utility.fastplace.FastPlaceModule; import dev.thoq.module.impl.utility.nofall.NoFallModule; -import dev.thoq.module.impl.movement.JumpCooldownModule; -import dev.thoq.module.impl.movement.SprintModule; import dev.thoq.module.impl.visual.*; import dev.thoq.module.impl.world.TimerModule; import dev.thoq.module.impl.visual.clickgui.ClickGUIModule; import dev.thoq.module.impl.visual.esp.ESPModule; import dev.thoq.utilities.misc.IconLoader; import dev.thoq.utilities.misc.RyeConstants; +import dev.thoq.utilities.render.Theme; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.util.InputUtil; +import net.minecraft.util.TimeHelper; import net.minecraft.util.math.Vec3d; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -152,7 +148,10 @@ private static void initializeModules() { new AmbienceModule(), new DiscordRPCModule(), new DisablerModule(), - new CapeModule() + new CapeModule(), + new AntiGravityModule(), + new AntiVoidModule(), + new TargetStrafeModule() ); } @@ -162,7 +161,8 @@ private static void initializeCommands() { new ToggleCommand(), new ConfigCommand(), new BindCommand(), - new SettingsCommand() + new SettingsCommand(), + new VClipCommand() ); } diff --git a/src/client/java/dev/thoq/command/impl/VClipCommand.java b/src/client/java/dev/thoq/command/impl/VClipCommand.java new file mode 100644 index 0000000..9a11227 --- /dev/null +++ b/src/client/java/dev/thoq/command/impl/VClipCommand.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.command.impl; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import dev.thoq.command.AbstractCommand; +import dev.thoq.utilities.misc.ChatUtility; +import net.minecraft.client.MinecraftClient; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; + +public class VClipCommand extends AbstractCommand { + public VClipCommand() { + super("vclip"); + } + + @Override + protected void build(LiteralArgumentBuilder builder) { + builder + .then(CommandManager.argument("distance", StringArgumentType.word()) + .executes(context -> { + String distanceStr = StringArgumentType.getString(context, "distance"); + try { + int distance = Integer.parseInt(distanceStr); + teleport(distance); + return 1; + } catch(NumberFormatException e) { + return 0; + } + })) + .executes(this::usage); + } + + private int usage(CommandContext serverCommandSourceCommandContext) { + ChatUtility.sendInfo("Usage: .vclip "); + return 1; + } + + private static void teleport(int distance) { + MinecraftClient mc = MinecraftClient.getInstance(); + + if(mc.player == null) return; + + double x = mc.player.getPos().x; + double y = mc.player.getPos().y + distance; + double z = mc.player.getPos().z; + + mc.player.setPosition(x, y, z); + } +} diff --git a/src/client/java/dev/thoq/mixin/client/ui/WatermarkTitleScreenMixin.java b/src/client/java/dev/thoq/mixin/client/ui/WatermarkTitleScreenMixin.java index 3d1dadb..bc2d729 100644 --- a/src/client/java/dev/thoq/mixin/client/ui/WatermarkTitleScreenMixin.java +++ b/src/client/java/dev/thoq/mixin/client/ui/WatermarkTitleScreenMixin.java @@ -17,6 +17,7 @@ package dev.thoq.mixin.client.ui; import dev.thoq.RyeClient; +import dev.thoq.utilities.misc.RyeConstants; import dev.thoq.utilities.render.ColorUtility; import dev.thoq.utilities.render.TextRendererUtility; import net.minecraft.client.gui.*; @@ -42,18 +43,30 @@ public void onHudRender(DrawContext context, int mouseX, int mouseY, float delta @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LogoDrawer;draw(Lnet/minecraft/client/gui/DrawContext;IF)V")) private void renderRyeLogo(LogoDrawer logoDrawer, DrawContext context, int width, float alpha) { - // don't draw the minecraft logo - String text = "Rye"; - int x = context.getScaledWindowWidth() / 2 - TextRendererUtility.getXlTextWidth(text) / 2; - int y = Math.round(context.getScaledWindowHeight() / 4.5f); + String versionText = RyeConstants.VERSION; + + int tX = context.getScaledWindowWidth() / 2 - TextRendererUtility.getXlTextWidth(text) / 2; + int tY = Math.round(context.getScaledWindowHeight() / 4.5f); + + int vX = tX + TextRendererUtility.getXlTextWidth(text); + int vY = tY - TextRendererUtility.getXlTextHeight() * 3; TextRendererUtility.renderXlText( context, text, ColorUtility.Colors.WHITE, - x, - y, + tX, + tY, + false + ); + + TextRendererUtility.renderText( + context, + versionText, + ColorUtility.Colors.WHITE, + vX, + vY, false ); } @@ -64,8 +77,7 @@ private void replaceVersionText(DrawContext context, net.minecraft.client.font.T // we ignore demo and modded - // I think I want to stop this - // its cleaner + // I think I want to stop this-its cleaner // context.drawTextWithShadow(textRenderer, ryeVersion, x, y, color); } diff --git a/src/client/java/dev/thoq/module/SubModule.java b/src/client/java/dev/thoq/module/SubModule.java index bcf4d66..b84b553 100644 --- a/src/client/java/dev/thoq/module/SubModule.java +++ b/src/client/java/dev/thoq/module/SubModule.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + package dev.thoq.module; import dev.thoq.RyeClient; @@ -26,6 +42,7 @@ public void onEnable() { } public void onDisable() { + reset(); RyeClient.getEventBus().unsubscribe(this); } @@ -36,4 +53,6 @@ public void addSettings(final Setting... settings) { } } + public void reset() { + } } diff --git a/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java b/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java index c939e48..b35a000 100644 --- a/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java +++ b/src/client/java/dev/thoq/module/impl/combat/killaura/KillauraModule.java @@ -511,6 +511,30 @@ private void stopBlocking() { isBlocking = false; } + /** + * Get the current attack mode for Target Strafe integration + * @return Current attack mode + */ + public String getAttackMode() { + return attackMode.getValue(); + } + + /** + * Get the current target for Target Strafe integration + * @return Current target entity + */ + public Entity getCurrentTarget() { + return currentTarget; + } + + /** + * Check if the module has valid targets + * @return true if there are valid targets + */ + public boolean hasTargets() { + return !targets.isEmpty(); + } + @Override protected void onEnable() { if(mc.player != null) { diff --git a/src/client/java/dev/thoq/module/impl/movement/AntiGravityModule.java b/src/client/java/dev/thoq/module/impl/movement/AntiGravityModule.java new file mode 100644 index 0000000..e695fcd --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/movement/AntiGravityModule.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.movement; + +import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; +import dev.thoq.module.Module; +import dev.thoq.module.ModuleCategory; +import dev.thoq.utilities.player.TimerUtility; + +public class AntiGravityModule extends Module { + public AntiGravityModule() { + super("AntiGravity", "Anti-Gravity", "Makes you feel like you're on the moon", ModuleCategory.MOVEMENT); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(mc.player == null) return; + + if(event.isPre()) { + if(mc.player.isOnGround()) + TimerUtility.setTimerSpeed(0.97); + else + TimerUtility.setTimerSpeed(0.87658); + } + }; + + @Override + public void onDisable() { + if(mc.player == null) return; + + TimerUtility.resetTimer(); + } +} diff --git a/src/client/java/dev/thoq/module/impl/movement/TargetStrafe.java b/src/client/java/dev/thoq/module/impl/movement/TargetStrafe.java deleted file mode 100644 index d08b48a..0000000 --- a/src/client/java/dev/thoq/module/impl/movement/TargetStrafe.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Rye Client 2024-2025. - * - * This file belongs to Rye Client, - * an open-source Fabric injection client. - * Rye GitHub: https://github.com/RyeClient/rye-v1.git - * - * THIS PROJECT DOES NOT HAVE A WARRANTY. - * - * Rye (and subsequently, its files) are all licensed under the MIT License. - * Rye should have come with a copy of the MIT License. - * If it did not, you may obtain a copy here: - * MIT License: https://opensource.org/license/mit - * - */ - -package dev.thoq.module.impl.movement; - -import dev.thoq.config.setting.impl.BooleanSetting; -import dev.thoq.config.setting.impl.ModeSetting; -import dev.thoq.config.setting.impl.NumberSetting; -import dev.thoq.module.Module; -import dev.thoq.module.ModuleCategory; -import net.minecraft.entity.Entity; - -// todo: unbork (implement) -public class TargetStrafe extends Module { - private final ModeSetting targetMode = new ModeSetting("Target", "Target types", "Players", "Players", "Passive", "Hostile", "All"); - private final NumberSetting range = new NumberSetting<>("Range", "Distance from target to strafe", 3.0f, 0.1f, 6.0f); - private final NumberSetting speed = new NumberSetting<>("Speed", "Strafe speed", 0.28f, 0.1f, 1.0f); - private final BooleanSetting adaptiveSpeed = new BooleanSetting("Adaptive Speed", "Adjust speed based on distance", true); - private final BooleanSetting jumpStrafe = new BooleanSetting("Jump Strafe", "Allow strafing in air", false); - - private Entity currentTarget = null; - private float strafeDirection = 1.0f; - private int directionChangeTimer = 0; - - public TargetStrafe() { - super("TargetStrafe", "Target Strafe", "Automatically move around targets", ModuleCategory.MOVEMENT); - addSetting(targetMode); - addSetting(range); - addSetting(speed); - addSetting(adaptiveSpeed); - addSetting(jumpStrafe); - } -} \ No newline at end of file diff --git a/src/client/java/dev/thoq/module/impl/movement/TargetStrafeModule.java b/src/client/java/dev/thoq/module/impl/movement/TargetStrafeModule.java new file mode 100644 index 0000000..20b952b --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/movement/TargetStrafeModule.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.movement; + +import dev.thoq.RyeClient; +import dev.thoq.config.setting.impl.BooleanSetting; +import dev.thoq.config.setting.impl.ModeSetting; +import dev.thoq.config.setting.impl.NumberSetting; +import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; +import dev.thoq.module.Module; +import dev.thoq.module.ModuleCategory; +import dev.thoq.module.impl.combat.killaura.KillauraModule; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.passive.PassiveEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.Vec3d; + +import java.util.Comparator; +import java.util.List; + +public class TargetStrafeModule extends Module { + private final ModeSetting targetMode = new ModeSetting("Target", "Target types", "Players", "Players", "Passive", "Hostile", "All"); + private final NumberSetting range = new NumberSetting<>("Range", "Distance from target to strafe", 3.0f, 0.1f, 6.0f); + private final NumberSetting speed = new NumberSetting<>("Speed", "Strafe speed", 0.28f, 0.1f, 1.0f); + private final BooleanSetting adaptiveSpeed = new BooleanSetting("Adaptive Speed", "Adjust speed based on distance", true); + private final BooleanSetting jumpStrafe = new BooleanSetting("Jump Strafe", "Allow strafing in air", false); + private final BooleanSetting onlyWhenKillaura = new BooleanSetting("Only with Killaura", "Only strafe when Killaura is enabled", true); + private final BooleanSetting autoJump = new BooleanSetting("Auto Jump", "Jump while strafing", false); + private final NumberSetting jumpChance = new NumberSetting<>("Jump Chance", "Chance to jump while strafing", 0.1f, 0.01f, 1.0f); + + private Entity currentTarget = null; + private float strafeDirection = 1.0f; + private int directionChangeTimer = 0; + private int jumpTimer = 0; + + public TargetStrafeModule() { + super("TargetStrafeModule", "Target Strafe", "Automatically move around targets", ModuleCategory.MOVEMENT); + + jumpChance.setVisibilityCondition(autoJump::getValue); + + addSetting(targetMode); + addSetting(range); + addSetting(speed); + addSetting(adaptiveSpeed); + addSetting(jumpStrafe); + addSetting(onlyWhenKillaura); + addSetting(autoJump); + addSetting(jumpChance); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if (mc.player == null || mc.world == null || !event.isPre()) return; + + if (onlyWhenKillaura.getValue()) { + KillauraModule killaura = RyeClient.INSTANCE.getModuleRepository().getModule(KillauraModule.class); + if (killaura == null || !killaura.isEnabled()) { + currentTarget = null; + return; + } + + String attackMode = killaura.getAttackMode(); + if (attackMode.equals("Single") || attackMode.equals("Switch")) { + Entity killauraTarget = killaura.getCurrentTarget(); + + if (killauraTarget != null) { + currentTarget = killauraTarget; + } else if (currentTarget != null && isValidStrafeTarget(currentTarget)) { + } else { + currentTarget = null; + } + } else { + currentTarget = null; + return; + } + } else { + findTarget(); + } + + if (currentTarget == null) return; + + if (!shouldStrafe()) return; + + performStrafe(); + + if (autoJump.getValue() && shouldJump()) { + mc.player.jump(); + } + }; + + private boolean isValidStrafeTarget(Entity entity) { + if (mc.player == null || entity == null || !entity.isAlive()) return false; + + double distance = mc.player.distanceTo(entity); + if (distance > range.getValue() * 1.5) return false; + + return isValidTarget(entity); + } + + private void findTarget() { + if (mc.player == null || mc.world == null) return; + + List entities = mc.world.getEntitiesByClass(Entity.class, + mc.player.getBoundingBox().expand(range.getValue()), + this::isValidTarget); + + if (entities.isEmpty()) { + currentTarget = null; + return; + } + + entities.sort(Comparator.comparingDouble(entity -> entity.squaredDistanceTo(mc.player))); + currentTarget = entities.getFirst(); + } + + private boolean isValidTarget(Entity entity) { + if (mc.player == null) return false; + if (!(entity instanceof LivingEntity) || entity == mc.player || !entity.isAlive()) { + return false; + } + + double distance = mc.player.distanceTo(entity); + if (distance > range.getValue()) return false; + + return switch (targetMode.getValue()) { + case "Players" -> entity instanceof PlayerEntity; + case "Passive" -> entity instanceof PassiveEntity; + case "Hostile" -> entity instanceof HostileEntity; + case "All" -> entity instanceof PlayerEntity || entity instanceof PassiveEntity || entity instanceof HostileEntity; + default -> false; + }; + } + + private boolean shouldStrafe() { + if (mc.player == null || currentTarget == null) return false; + + if (!currentTarget.isAlive()) { + currentTarget = null; + return false; + } + + double distance = mc.player.distanceTo(currentTarget); + + if (distance > range.getValue() * 1.2) { + currentTarget = null; + return false; + } + + return mc.player.isOnGround() || jumpStrafe.getValue(); + } + + private void performStrafe() { + if (mc.player == null || currentTarget == null) return; + + Vec3d playerPos = mc.player.getPos(); + Vec3d targetPos = currentTarget.getPos(); + + double deltaX = targetPos.x - playerPos.x; + double deltaZ = targetPos.z - playerPos.z; + + float angleToTarget = (float) Math.toDegrees(Math.atan2(deltaZ, deltaX)) - 90.0f; + + float strafeAngle = angleToTarget + (90.0f * strafeDirection); + + if (directionChangeTimer++ >= 60) { + strafeDirection = -strafeDirection; + directionChangeTimer = 0; + } + + float currentSpeed = speed.getValue(); + + if (adaptiveSpeed.getValue()) { + double distance = mc.player.distanceTo(currentTarget); + float targetDistance = range.getValue() * 0.7f; + float distanceRatio = (float) (distance / targetDistance); + + if (distanceRatio < 0.8f) { + currentSpeed *= 1.2f; + } else if (distanceRatio > 1.2f) { + currentSpeed *= 0.8f; + } + } + + double radians = Math.toRadians(strafeAngle); + double xMotion = -Math.sin(radians) * currentSpeed; + double zMotion = Math.cos(radians) * currentSpeed; + + Vec3d currentVelocity = mc.player.getVelocity(); + mc.player.setVelocity(xMotion, currentVelocity.y, zMotion); + } + + private boolean shouldJump() { + if (mc.player == null) return false; + + if (!mc.player.isOnGround()) return false; + + if (jumpTimer > 0) { + jumpTimer--; + return false; + } + + if (Math.random() > jumpChance.getValue()) return false; + + jumpTimer = 10; + return true; + } + + @Override + protected void onEnable() { + currentTarget = null; + directionChangeTimer = 0; + jumpTimer = 0; + strafeDirection = 1.0f; + } + + @Override + protected void onDisable() { + currentTarget = null; + directionChangeTimer = 0; + jumpTimer = 0; + } + + public Entity getCurrentTarget() { + return currentTarget; + } + + public boolean isStrafing() { + return isEnabled() && currentTarget != null; + } +} \ No newline at end of file diff --git a/src/client/java/dev/thoq/module/impl/movement/flight/FlightModule.java b/src/client/java/dev/thoq/module/impl/movement/flight/FlightModule.java index 17bbb50..4566efa 100644 --- a/src/client/java/dev/thoq/module/impl/movement/flight/FlightModule.java +++ b/src/client/java/dev/thoq/module/impl/movement/flight/FlightModule.java @@ -25,14 +25,19 @@ import dev.thoq.module.impl.movement.flight.verus.VerusPacketFlight; import net.minecraft.client.option.GameOptions; -@SuppressWarnings("unchecked") public class FlightModule extends Module { private boolean wasSprinting = false; public FlightModule() { super("Flight", "Become airplane", ModuleCategory.MOVEMENT); - this.addSubmodules(new NormalFlight(this), new CreativeFlight(this), new VerusPacketFlight(this), new VerusDamageFly(this), new VerusGlideFly(this)); + this.addSubmodules( + new NormalFlight(this), + new CreativeFlight(this), + new VerusPacketFlight(this), + new VerusDamageFly(this), + new VerusGlideFly(this) + ); } @Override diff --git a/src/client/java/dev/thoq/module/impl/movement/flight/vanilla/NormalFlight.java b/src/client/java/dev/thoq/module/impl/movement/flight/vanilla/NormalFlight.java index 0aaf1f4..cc68aa4 100644 --- a/src/client/java/dev/thoq/module/impl/movement/flight/vanilla/NormalFlight.java +++ b/src/client/java/dev/thoq/module/impl/movement/flight/vanilla/NormalFlight.java @@ -53,7 +53,7 @@ else if(down) } if(this.preventVanillaKick.getValue() && !verticalMovement) - MoveUtility.setMotionY(MoveUtility.getVanillaFallingSpeed()); + MoveUtility.setMotionY(MoveUtility.getVanillaFallingSpeed() + 0.05); else if(!verticalMovement) MoveUtility.setMotionY(0); diff --git a/src/client/java/dev/thoq/module/impl/movement/flight/verus/VerusGlideFly.java b/src/client/java/dev/thoq/module/impl/movement/flight/verus/VerusGlideFly.java index 0c16adf..d594c97 100644 --- a/src/client/java/dev/thoq/module/impl/movement/flight/verus/VerusGlideFly.java +++ b/src/client/java/dev/thoq/module/impl/movement/flight/verus/VerusGlideFly.java @@ -23,7 +23,6 @@ import dev.thoq.module.SubModule; import dev.thoq.utilities.misc.ChatUtility; import dev.thoq.utilities.player.MoveUtility; -import net.minecraft.client.MinecraftClient; public class VerusGlideFly extends SubModule { @@ -37,11 +36,18 @@ public VerusGlideFly(final Module parent) { this.addSettings(this.clip); } + @SuppressWarnings("unused") private final IEventListener onMotion = event -> { if(!event.isPre()) return; if(mc.player == null) return; + + if(mc.player.isOnGround()) { + ChatUtility.sendError("Please be in air before toggling!"); + return; + } + if(!messageSent) { - ChatUtility.sendWarning("This fly does *NOT* new Verus, only old cracked versions!"); + ChatUtility.sendWarning("This fly may not work on new Verus (its iffy), it does work on old cracked versions!"); messageSent = true; } @@ -51,13 +57,13 @@ public VerusGlideFly(final Module parent) { timeRunning++; - if(clip.getValue() && timeRunning >= 80) { - mc.player.setPosition(posX, posY + 1, posZ); + if(clip.getValue() && timeRunning >= 90) { + mc.player.setPosition(posX, posY + 2, posZ); timeRunning = 0; } MoveUtility.setMotionY(-0.02); - MoveUtility.setSpeed(0.1); + MoveUtility.setSpeed(0.3, true); }; @Override diff --git a/src/client/java/dev/thoq/module/impl/movement/longjump/verus/VerusPacketLongjump.java b/src/client/java/dev/thoq/module/impl/movement/longjump/verus/VerusPacketLongjump.java index dff09bc..204988c 100644 --- a/src/client/java/dev/thoq/module/impl/movement/longjump/verus/VerusPacketLongjump.java +++ b/src/client/java/dev/thoq/module/impl/movement/longjump/verus/VerusPacketLongjump.java @@ -27,7 +27,7 @@ import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; public class VerusPacketLongjump extends SubModule { - + private final PlayerUtility playerUtility = new PlayerUtility(); static boolean jumped = false; static boolean damaged = false; static boolean waitingForGround = false; @@ -40,7 +40,7 @@ public VerusPacketLongjump(final Module parent) { if(mc.player == null) return; if(!damaged && !waitingForGround) { - PlayerUtility.applyDamage(mc, 3); + playerUtility.applyDamage(mc, 3); damaged = true; waitingForGround = true; } diff --git a/src/client/java/dev/thoq/module/impl/movement/speed/SpeedModule.java b/src/client/java/dev/thoq/module/impl/movement/speed/SpeedModule.java index 0ae171e..7b06134 100644 --- a/src/client/java/dev/thoq/module/impl/movement/speed/SpeedModule.java +++ b/src/client/java/dev/thoq/module/impl/movement/speed/SpeedModule.java @@ -21,6 +21,7 @@ import dev.thoq.module.impl.movement.speed.blocksmc.BlocksMCSpeed; import dev.thoq.module.impl.movement.speed.ncp.NCPSpeed; import dev.thoq.module.impl.movement.speed.normal.NormalSpeed; +import dev.thoq.module.impl.movement.speed.spartan.SpartanSpeed; import dev.thoq.module.impl.movement.speed.verus.VerusSpeed; import dev.thoq.utilities.player.TimerUtility; @@ -34,7 +35,8 @@ public SpeedModule() { new NormalSpeed(this), new NCPSpeed(this), new VerusSpeed(this), - new BlocksMCSpeed(this) + new BlocksMCSpeed(this), + new SpartanSpeed(this) ); } diff --git a/src/client/java/dev/thoq/module/impl/movement/speed/spartan/SpartanSpeed.java b/src/client/java/dev/thoq/module/impl/movement/speed/spartan/SpartanSpeed.java new file mode 100644 index 0000000..6490c5c --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/movement/speed/spartan/SpartanSpeed.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.movement.speed.spartan; + +import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; +import dev.thoq.module.Module; +import dev.thoq.module.SubModule; +import dev.thoq.utilities.misc.ChatUtility; +import dev.thoq.utilities.player.MoveUtility; + +public class SpartanSpeed extends SubModule { + private int ticks = 0; + + public SpartanSpeed(Module parent) { + super("Spartan", parent); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(!event.isPre()) return; + if(this.mc.player == null) return; + + if(mc.player.isOnGround()) { + ticks = 0; + } else { + ticks++; + + if(ticks == 1) { + if(MoveUtility.getSpeed() < 0.8) { + MoveUtility.setSpeed(0.8, true); + } else { + MoveUtility.setSpeed(MoveUtility.getSpeed() * 2.5, true); + } + } + } + }; + + @Override + public void reset() { + ticks = 0; + } +} diff --git a/src/client/java/dev/thoq/module/impl/movement/speed/verus/VerusSpeed.java b/src/client/java/dev/thoq/module/impl/movement/speed/verus/VerusSpeed.java index 0509f9a..2f9c717 100644 --- a/src/client/java/dev/thoq/module/impl/movement/speed/verus/VerusSpeed.java +++ b/src/client/java/dev/thoq/module/impl/movement/speed/verus/VerusSpeed.java @@ -41,7 +41,7 @@ public VerusSpeed(final Module parent) { return; if(forwardOnly) - MoveUtility.setSpeed(0.29f, true); + MoveUtility.setSpeed(0.285f, true); else MoveUtility.setSpeed(0.26f, true); diff --git a/src/client/java/dev/thoq/module/impl/utility/antivoid/AntiVoidModule.java b/src/client/java/dev/thoq/module/impl/utility/antivoid/AntiVoidModule.java new file mode 100644 index 0000000..4a558ac --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/utility/antivoid/AntiVoidModule.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.utility.antivoid; + +import dev.thoq.module.Module; +import dev.thoq.module.ModuleCategory; +import dev.thoq.module.impl.utility.antivoid.position.PositionAntiVoid; + +public class AntiVoidModule extends Module { + public AntiVoidModule() { + super("AntiVoid", "Anti-Void", "Prevents you from falling in the void", ModuleCategory.UTILITY); + + this.addSubmodules( + new PositionAntiVoid(this) + ); + } + + @Override + public void onEnable() { + super.onEnable(); + } + + @Override + public void onDisable() { + super.onDisable(); + } +} diff --git a/src/client/java/dev/thoq/module/impl/utility/antivoid/position/PositionAntiVoid.java b/src/client/java/dev/thoq/module/impl/utility/antivoid/position/PositionAntiVoid.java new file mode 100644 index 0000000..f230b06 --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/utility/antivoid/position/PositionAntiVoid.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.utility.antivoid.position; + +import dev.thoq.config.setting.impl.NumberSetting; +import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; +import dev.thoq.module.Module; +import dev.thoq.module.SubModule; +import dev.thoq.utilities.misc.ChatUtility; +import dev.thoq.utilities.player.PlayerUtility; + +/** + * @author slqnt + * @since 0.1 + */ +public class PositionAntiVoid extends SubModule { + private final PlayerUtility playerUtility = new PlayerUtility(); + private final NumberSetting distance = new NumberSetting<>("Distance", "Distance to check for void", 4, 1, 10); + + public PositionAntiVoid(Module parent) { + super("Position", parent); + + this.addSettings(distance); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(mc.player == null || !event.isPre()) return; + + boolean isOverVoid = playerUtility.isOverVoid(); + boolean isFalling = mc.player.fallDistance > distance.getValue(); + + ChatUtility.sendDebug("Is over void:" + isOverVoid); + ChatUtility.sendDebug("Is falling:" + isFalling); + if(isFalling && isOverVoid) { + event.setY(event.getY() + mc.player.fallDistance); + } + }; + +} diff --git a/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java b/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java index 8334846..525ed30 100644 --- a/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java +++ b/src/client/java/dev/thoq/module/impl/utility/disabler/DisablerModule.java @@ -16,50 +16,30 @@ package dev.thoq.module.impl.utility.disabler; -import dev.thoq.config.setting.impl.MultipleBooleanSetting; -import dev.thoq.event.IEventListener; -import dev.thoq.event.impl.MotionEvent; -import dev.thoq.event.impl.PacketSendEvent; -import dev.thoq.event.impl.TickEvent; import dev.thoq.module.Module; import dev.thoq.module.ModuleCategory; import dev.thoq.module.impl.utility.disabler.cubecraft.CubecraftDisabler; import dev.thoq.module.impl.utility.disabler.omnisprint.OmniSprintDisabler; -import io.netty.util.internal.SuppressJava6Requirement; +import dev.thoq.module.impl.utility.disabler.spartan.SpartanDisabler; public class DisablerModule extends Module { - private final OmniSprintDisabler omniSprintDisabler = new OmniSprintDisabler(); - private final CubecraftDisabler cubecraftDisabler = new CubecraftDisabler(); - - private final MultipleBooleanSetting disabler = new MultipleBooleanSetting("Mode", "Disabler mode", "OmniSprint", "Cubecraft"); - public DisablerModule() { super("Disabler", "Partially or fully disable some anticheats", ModuleCategory.UTILITY); - addSetting(disabler); + this.addSubmodules( + new SpartanDisabler(this), + new OmniSprintDisabler(this), + new CubecraftDisabler(this) + ); } - @SuppressWarnings("unused") - private final IEventListener tickEvent = event -> { - if(disabler.getEnabledOptions().isEmpty()) - setPrefix("None"); - else if(disabler.getEnabledOptions().size() > 1) - setPrefix("Multi"); - else - setPrefix(disabler.getEnabledOptions().getFirst()); - }; - - @SuppressWarnings({"unused"}) - private final IEventListener packetSendEvent = event -> { - if(disabler.isEnabled("OmniSprint")) { - omniSprintDisabler.omniSprintDisabler(event, mc); - } - }; + @Override + public void onEnable() { + super.onEnable(); + } - @SuppressWarnings("unused") - private final IEventListener motionEvent = event -> { - if(disabler.isEnabled("Cubecraft")) { - cubecraftDisabler.cubecraftDisabler(event, mc); - } - }; -} \ No newline at end of file + @Override + public void onDisable() { + super.onDisable(); + } +} diff --git a/src/client/java/dev/thoq/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java b/src/client/java/dev/thoq/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java index 4990897..c004e8d 100644 --- a/src/client/java/dev/thoq/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java +++ b/src/client/java/dev/thoq/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java @@ -16,13 +16,22 @@ package dev.thoq.module.impl.utility.disabler.cubecraft; +import dev.thoq.event.IEventListener; import dev.thoq.event.impl.MotionEvent; +import dev.thoq.event.impl.PacketSendEvent; +import dev.thoq.module.Module; +import dev.thoq.module.SubModule; import net.minecraft.client.MinecraftClient; -public class CubecraftDisabler { - public void cubecraftDisabler(MotionEvent event, MinecraftClient mc) { +public class CubecraftDisabler extends SubModule { + public CubecraftDisabler(Module parent) { + super("Cubecraft", parent); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { if(mc.player == null) return; event.setOnGround(mc.player.age % 2 == 0); - } + }; } diff --git a/src/client/java/dev/thoq/module/impl/utility/disabler/omnisprint/OmniSprintDisabler.java b/src/client/java/dev/thoq/module/impl/utility/disabler/omnisprint/OmniSprintDisabler.java index 887c4b8..7c951df 100644 --- a/src/client/java/dev/thoq/module/impl/utility/disabler/omnisprint/OmniSprintDisabler.java +++ b/src/client/java/dev/thoq/module/impl/utility/disabler/omnisprint/OmniSprintDisabler.java @@ -16,14 +16,21 @@ package dev.thoq.module.impl.utility.disabler.omnisprint; +import dev.thoq.event.IEventListener; import dev.thoq.event.impl.PacketSendEvent; -import net.minecraft.client.MinecraftClient; +import dev.thoq.module.Module; +import dev.thoq.module.SubModule; import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; -public class OmniSprintDisabler { +public class OmniSprintDisabler extends SubModule { private static boolean serverSprintState = false; - public void omniSprintDisabler(PacketSendEvent event, MinecraftClient mc) { + public OmniSprintDisabler(Module parent) { + super("OmniSprint", parent); + } + + @SuppressWarnings("unused") + private final IEventListener packetSendEvent = event -> { if(mc.player == null || mc.getNetworkHandler() == null) return; if(event.getPacket() instanceof ClientCommandC2SPacket packet) { @@ -37,5 +44,5 @@ public void omniSprintDisabler(PacketSendEvent event, MinecraftClient mc) { event.cancel(); } } - } + }; } \ No newline at end of file diff --git a/src/client/java/dev/thoq/module/impl/utility/disabler/spartan/SpartanDisabler.java b/src/client/java/dev/thoq/module/impl/utility/disabler/spartan/SpartanDisabler.java new file mode 100644 index 0000000..586a305 --- /dev/null +++ b/src/client/java/dev/thoq/module/impl/utility/disabler/spartan/SpartanDisabler.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.module.impl.utility.disabler.spartan; + +import dev.thoq.event.IEventListener; +import dev.thoq.event.impl.MotionEvent; +import dev.thoq.module.Module; +import dev.thoq.module.SubModule; +import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket; +import net.minecraft.util.Hand; + +public class SpartanDisabler extends SubModule { + private static int timeRunning = 0; + + public SpartanDisabler(Module parent) { + super("Spartan", parent); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(mc.player == null || mc.getNetworkHandler() == null) return; + if(!event.isPre()) return; + + timeRunning++; + + PlayerInteractItemC2SPacket playerInteractItemC2SPacket = new PlayerInteractItemC2SPacket( + Hand.MAIN_HAND, + 0, + mc.player.getYaw(), + mc.player.getPitch() + ); + + if(timeRunning > 20) { + mc.getNetworkHandler().sendPacket(playerInteractItemC2SPacket); + timeRunning = 0; + } + }; + + @Override + public void reset() { + timeRunning = 0; + } +} diff --git a/src/client/java/dev/thoq/module/impl/visual/ArraylistModule.java b/src/client/java/dev/thoq/module/impl/visual/ArraylistModule.java index 6b02db4..b47ea88 100644 --- a/src/client/java/dev/thoq/module/impl/visual/ArraylistModule.java +++ b/src/client/java/dev/thoq/module/impl/visual/ArraylistModule.java @@ -88,16 +88,14 @@ private int getWaveColor(int index, int totalModules) { float time = System.currentTimeMillis() / 1000.0f; float waveOffset = (float) index / Math.max(1, totalModules - 1); float phase = time * 2.0f + waveOffset * 4.0f; - - Theme currentTheme = Theme.getCurrentTheme(); float factor = (float) (Math.sin(phase) + 1.0) / 2.0f; - return Theme.interpolateColorInt(currentTheme.getPrimaryColor(), currentTheme.getSecondaryColor(), factor); + return Theme.getInterpolatedColors(factor); } /** - * Gets the full display name for a module including any prefixes - * Format: ModuleName [ModulePrefix] + * Gets the full display name for a module including any suffixes + * Format: ModuleName [Suffix] */ private String getModuleDisplayName(Module module) { StringBuilder displayName = new StringBuilder(); diff --git a/src/client/java/dev/thoq/module/impl/visual/HUDModule.java b/src/client/java/dev/thoq/module/impl/visual/HUDModule.java index 6773542..b1dafb0 100644 --- a/src/client/java/dev/thoq/module/impl/visual/HUDModule.java +++ b/src/client/java/dev/thoq/module/impl/visual/HUDModule.java @@ -17,395 +17,184 @@ package dev.thoq.module.impl.visual; import dev.thoq.RyeClient; -import dev.thoq.config.setting.impl.ModeSetting; import dev.thoq.event.IEventListener; import dev.thoq.event.impl.Render2DEvent; import dev.thoq.module.Module; import dev.thoq.module.ModuleCategory; -import dev.thoq.module.impl.world.NukerModule; -import dev.thoq.module.impl.combat.ReachModule; import dev.thoq.utilities.render.ColorUtility; import dev.thoq.utilities.render.RenderUtility; import dev.thoq.utilities.render.TextRendererUtility; import dev.thoq.utilities.render.Theme; -import org.jetbrains.annotations.NotNull; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; +import org.joml.Vector4f; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -@SuppressWarnings({"FieldCanBeLocal", "SameParameterValue", "unused"}) public class HUDModule extends Module { - - private long animationStartTime = 0; - private boolean isAnimatingIn = false; - private boolean isAnimatingOut = false; - private boolean wasVisible = false; - private static final long ANIMATION_DURATION = 200; - private static final int END_Y_POSITION = 30; - private static String lastDynamicText = ""; - private final ModeSetting themeSetting; - private int targetModuleCount = 0; - private float currentModuleCount = 0; - private long expansionStartTime = 0; - private boolean isExpanding = false; - private static final long EXPANSION_DURATION = 300; + private final List bpsHistory = new ArrayList<>(); public HUDModule() { super("HUD", "Shows Heads Up Display", ModuleCategory.VISUAL); - String[] themeNames = Theme.getThemeNames(); - this.themeSetting = new ModeSetting("Theme", "Select the theme for the HUD", "Rye", themeNames); - this.addSetting(themeSetting); - this.setEnabled(true); } - private enum Mode { - NORMAL, - SCAFFOLD, - SPEED, - FLIGHT, - KILLAURA, - NUKER, - REACH, - } - + @SuppressWarnings("unused") private final IEventListener renderEvent = event -> { if(mc.player == null) return; - boolean killauraEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Killaura").isEnabled(); - boolean scaffoldEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Scaffold").isEnabled(); - boolean speedEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Speed").isEnabled(); - boolean flightEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Flight").isEnabled(); - boolean nukerEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Nuker").isEnabled(); - boolean reachEnabled = RyeClient.INSTANCE.getModuleRepository().getModuleByName("Reach").isEnabled(); - - List dynamicTexts = new ArrayList<>(); - String bps = RyeClient.getBps(); - - if(flightEnabled || speedEnabled) { - String speedFlightMsg = String.format("Going %s b/s", bps); - dynamicTexts.add(speedFlightMsg); - } - - if(scaffoldEnabled) { - int scaffoldSlot = mc.player.getInventory().getSelectedSlot(); - int blocksRemaining = mc.player.getInventory().getStack(scaffoldSlot).getCount(); - String scaffoldMsg = String.format("%s Remaining", blocksRemaining); - dynamicTexts.add(scaffoldMsg); - } + final int padding = 7; + final int xPosition = 4; + final int yPosition = 2; + final Vector4f radius = new Vector4f(10f, 10f, 10f, 10f); + final int rectWidth = 200; + final int rectHeight = 120; + final int maxHistorySize = 200; - if(killauraEnabled) { - String killauraMsg = String.format("%.1f/%.1f ♡", - mc.player.getHealth() / 2, mc.player.getMaxHealth() / 2); - dynamicTexts.add(killauraMsg); - } + RenderUtility.drawImage( + Identifier.of("rye", "images/rye_logo_white.png"), + xPosition, + yPosition, + xPosition + padding * 6, + yPosition + padding * 3, + xPosition + padding * 6, + yPosition + padding * 3, + event.getContext() + ); - if(nukerEnabled) { - String nukerMsg = String.format("%s blocks destroyed", NukerModule.getBlocksDestroyed()); - dynamicTexts.add(nukerMsg); - } + RenderUtility.drawGradientRoundedRect( + event.getContext(), + xPosition, + yPosition + (padding * 5), + rectWidth, + rectHeight, + radius, + Theme.COLOR$1, + Theme.COLOR$2 + ); - if(reachEnabled) { - String reachMsg = String.format("Reached %.1f blocks", ReachModule.getLastReach()); - dynamicTexts.add(reachMsg); - } + String currentBps = RyeClient.getBps(); + double bpsValue = Double.parseDouble(currentBps); - int newModuleCount = dynamicTexts.size(); - if(newModuleCount != targetModuleCount) { - targetModuleCount = newModuleCount; - startExpansionAnimation(); + bpsHistory.add(bpsValue); + if(bpsHistory.size() > maxHistorySize) { + bpsHistory.removeFirst(); } - updateExpansionAnimation(); + int contentX = xPosition + padding; + int contentY = yPosition + (padding * 5) + 10; + int graphY; + int graphHeight = 30; + int graphWidth = rectWidth - (padding * 6); + int cordsY = mc.getWindow().getScaledHeight() - 10; + Vec3d position = mc.player.getPos(); + String cordsText = String.format("XYZ: %.1f %.1f %.1f", position.x, position.y, position.z); + contentY += 3; + + TextRendererUtility.renderMdText( + event.getContext(), + "Statistics", + ColorUtility.Colors.WHITE, + contentX, + contentY, + false + ); - String time = RyeClient.getTime(); - String fps = RyeClient.getFps(); - String name = mc.player.getName().getString(); + contentY += TextRendererUtility.getMdTextHeight() + (padding * 2); - String clientName = createAnimatedClientName(); + TextRendererUtility.renderText( + event.getContext(), + "FPS: " + RyeClient.getFps(), + ColorUtility.Colors.WHITE, + contentX, + contentY, + false + ); - boolean shouldShowDynamic = !dynamicTexts.isEmpty(); + contentY += TextRendererUtility.getTextHeight() + 2; - if(shouldShowDynamic && !wasVisible) { - startShowAnimation(); - } else if(!shouldShowDynamic && wasVisible) { - startHideAnimation(); - } - - wasVisible = shouldShowDynamic; + TextRendererUtility.renderText( + event.getContext(), + "BPS: " + currentBps, + ColorUtility.Colors.WHITE, + contentX, + contentY, + false + ); - if(shouldShowDynamic || isAnimatingOut) { - drawAnimatedDynamicModules( - dynamicTexts, - event - ); - } + contentY += 20; - String displayText = String.format( - " %s | %s f/s | %s | %s", - clientName, - fps, - name, - time + TextRendererUtility.renderText( + event.getContext(), + "Speed Monitor", + ColorUtility.Colors.WHITE, + contentX, + contentY, + false ); - final int padding = 15; - final int textWidth = TextRendererUtility.getTextWidth(displayText); - final int textHeight = mc.textRenderer.fontHeight; - final int xPosition = 2; - final int yPosition = 2; - - int backgroundColor = ColorUtility.getColor(ColorUtility.Colors.PANEL); + contentY += TextRendererUtility.getTextHeight() + 2; + graphY = contentY; RenderUtility.drawRect( event.getContext(), - xPosition, - yPosition, - textWidth + padding, - textHeight + padding, - backgroundColor - ); - - renderAnimatedHUDText( - event, - displayText, - xPosition + padding / 2, - yPosition + padding / 2 + contentX, + graphY, + graphWidth, + graphHeight, + 0x44FFFFFF ); - }; - - private void startExpansionAnimation() { - expansionStartTime = System.currentTimeMillis(); - isExpanding = true; - } - - private void updateExpansionAnimation() { - if(!isExpanding) return; - - long elapsed = System.currentTimeMillis() - expansionStartTime; - float progress = Math.min(elapsed / (float) EXPANSION_DURATION, 1.0f); - float easedProgress = 1.0f - (float) Math.pow(1.0f - progress, 3); + if(bpsHistory.size() > 1) { + double maxBps = bpsHistory.stream().mapToDouble(d -> d).max().orElse(10.0); + maxBps = Math.max(maxBps, 10.0); - currentModuleCount = currentModuleCount + (targetModuleCount - currentModuleCount) * easedProgress; + for(int i = 1; i < bpsHistory.size(); i++) { + double prevBps = bpsHistory.get(i - 1); + double currBps = bpsHistory.get(i); - if(progress >= 1.0f) { - currentModuleCount = targetModuleCount; - isExpanding = false; - } - } - - private String createAnimatedClientName() { - return "§r§l" + RyeClient.getName() + "§r"; - } - - private void renderAnimatedHUDText(Render2DEvent event, String text, int x, int y) { - float time = System.currentTimeMillis() / 1000.0f; - float animationFactor = (float) (Math.sin(time * 2.0) + 1.0) / 2.0f; + int x1 = contentX + (int)((double)(i - 1) / (bpsHistory.size() - 1) * graphWidth); + int y1 = graphY + graphHeight - (int)(prevBps / maxBps * graphHeight); + int x2 = contentX + (int)((double)i / (bpsHistory.size() - 1) * graphWidth); + int y2 = graphY + graphHeight - (int)(currBps / maxBps * graphHeight); - String[] parts = text.split("§theme"); - if(parts.length > 1) { - if(!parts[0].isEmpty()) { - TextRendererUtility.renderText( + RenderUtility.drawLine( event.getContext(), - parts[0], - ColorUtility.Colors.WHITE, - x, - y, - false + x1, y1, x2, y2, + 2f, + ColorUtility.getColor(ColorUtility.Colors.WHITE) ); } - - int firstPartWidth = parts[0].isEmpty() ? 0 : TextRendererUtility.getTextWidth(parts[0]); - - String firstChar = String.valueOf(parts[1].charAt(0)); - int themeColor = Theme.getInterpolatedThemeColorInt(animationFactor); - - TextRendererUtility.renderText( - event.getContext(), - "§l" + firstChar, - themeColor, - x + firstPartWidth, - y, - false - ); - - int firstCharWidth = TextRendererUtility.getTextWidth("§l" + firstChar); - - String remainingText = "§r§l" + parts[1].substring(1) + "§r"; - TextRendererUtility.renderText( - event.getContext(), - remainingText, - ColorUtility.Colors.WHITE, - x + firstPartWidth + firstCharWidth, - y, - false - ); - } else { - TextRendererUtility.renderText( - event.getContext(), - text, - ColorUtility.Colors.WHITE, - x, - y, - false - ); - } - } - - private void startShowAnimation() { - animationStartTime = System.currentTimeMillis(); - isAnimatingIn = true; - isAnimatingOut = false; - } - - private void startHideAnimation() { - animationStartTime = System.currentTimeMillis(); - isAnimatingIn = false; - isAnimatingOut = true; - } - - private float getAnimationProgress() { - long elapsed = System.currentTimeMillis() - animationStartTime; - float progress = Math.min(elapsed / (float) ANIMATION_DURATION, 1.0f); - - return 1.0f - (float) Math.pow(1.0f - progress, 3); - } - - private void drawAnimatedDynamicModules( - List dynamicTexts, - Render2DEvent event - ) { - if(mc.player == null || dynamicTexts.isEmpty()) return; - - float progress = getAnimationProgress(); - - if(progress >= 1.0f) { - if(isAnimatingOut) { - isAnimatingOut = false; - return; - } - if(isAnimatingIn) { - isAnimatingIn = false; - } - } - - float animatedProgress; - if(isAnimatingIn) { - animatedProgress = progress; - } else if(isAnimatingOut) { - animatedProgress = 1.0f - progress; - } else { - animatedProgress = 1.0f; } - final int hudPadding = 15; - final int hudTextWidth = TextRendererUtility.getTextWidth(String.format( - " %s | %s f/s | %s | %s", - createAnimatedClientName(), - RyeClient.getFps(), - mc.player.getName().getString(), - new SimpleDateFormat("hh:mm a").format(new Date()) - )); - - final int hudBottomY = 2 + mc.textRenderer.fontHeight + hudPadding; - final int startY = hudBottomY - 10; - final int animatedY = (int) (startY + (END_Y_POSITION - startY) * animatedProgress); - - int alpha = (int) (255 * animatedProgress); - int baseBackgroundColor = ColorUtility.getColor(ColorUtility.Colors.PANEL); - - String displayText = getString(dynamicTexts); - - final int dynamicPadding = 15; - final int dynamicTextWidth = TextRendererUtility.getTextWidth(displayText); - final int dynamicWidth = dynamicTextWidth + dynamicPadding; - final int screenWidth = mc.getWindow().getScaledWidth(); - final int hudX = 2; - final int maxAllowedX = screenWidth - dynamicWidth; - final int alignedX = Math.min(hudX, maxAllowedX); - - drawDynamicRect( - displayText, - event, - alignedX, - animatedY, - dynamicPadding, - baseBackgroundColor, - alpha + String maxLabel = String.format("%.1f", bpsHistory.stream().mapToDouble(d -> d).max().orElse(10.0)); + TextRendererUtility.renderText( + event.getContext(), + maxLabel, + ColorUtility.Colors.LIGHT_GRAY, + contentX + graphWidth + 5, + graphY, + false ); - } - - private @NotNull String getString(List dynamicTexts) { - int modulesToShow = Math.min(dynamicTexts.size(), (int) Math.ceil(currentModuleCount)); - - StringBuilder combinedText = new StringBuilder(); - for(int i = 0; i < modulesToShow; i++) { - if(i > 0) combinedText.append(" | "); - - String moduleText = dynamicTexts.get(i); - - if(i >= (int) currentModuleCount) { - float partialProgress = currentModuleCount - (int) currentModuleCount; - int charactersToShow = (int) (moduleText.length() * partialProgress); - if(charactersToShow > 0) { - combinedText.append(moduleText, 0, Math.min(charactersToShow, moduleText.length())); - } - } else { - combinedText.append(moduleText); - } - } - - return combinedText.toString(); - } - - private int applyAlpha(int color, int alpha) { - int r = (color >> 16) & 0xFF; - int g = (color >> 8) & 0xFF; - int b = color & 0xFF; - int originalAlpha = (color >> 24) & 0xFF; - int combinedAlpha = (originalAlpha * alpha) / 255; - - return (combinedAlpha << 24) | (r << 16) | (g << 8) | b; - } - - private static void drawDynamicRect( - String displayText, - Render2DEvent event, - int xPosition, - int yPosition, - int padding, - int backgroundColor, - int textAlpha - ) { - int textWidth = TextRendererUtility.getTextWidth(displayText); - int textHeight = TextRendererUtility.getTextHeight(); - - lastDynamicText = displayText; - - RenderUtility.drawRect( + TextRendererUtility.renderText( event.getContext(), - xPosition, - yPosition, - textWidth + padding, - textHeight + padding, - backgroundColor + "0.0", + ColorUtility.Colors.LIGHT_GRAY, + contentX + graphWidth + 5, + graphY + graphHeight - TextRendererUtility.getTextHeight(), + false ); - int textColor = ColorUtility.getColor(ColorUtility.Colors.WHITE); - int animatedTextColor = (textAlpha << 24) | (textColor & 0x00FFFFFF); - TextRendererUtility.renderText( event.getContext(), - displayText, - animatedTextColor, - xPosition + padding / 2, - yPosition + padding / 2, - true + cordsText, + ColorUtility.Colors.WHITE, + xPosition - 1, + cordsY, + false ); - } + }; } \ No newline at end of file diff --git a/src/client/java/dev/thoq/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java b/src/client/java/dev/thoq/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java index c481f99..a558e5e 100644 --- a/src/client/java/dev/thoq/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java +++ b/src/client/java/dev/thoq/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java @@ -57,20 +57,18 @@ public class DropDownClickGUI extends Screen { private static final int BACKGROUND_COLOR = ColorUtility.getColor(ColorUtility.Colors.GRAY); private static final int CATEGORY_COLOR = 0xFF222222; private static final int HOVER_COLOR = 0x10FFFFFF; - private static final float CORNER_RADIUS = 5.0f; + private static final float CORNER_RADIUS = 4f; private static final int TOOLTIP_BACKGROUND = 0xFF000000; private static final int TOOLTIP_BORDER = 0xFF212121; private static final int TOOLTIP_MAX_WIDTH = 200; private static final int TOOLTIP_PADDING = 2; private static final int TOOLTIP_OFFSET = 10; - private String hoveredTooltip = null; private int tooltipX = 0; private int tooltipY = 0; private final boolean showTooltips; private int scrollOffset = 0; private ModuleCategory draggingCategory = null; - private boolean draggingNumberSetting = false; private NumberSetting currentDraggedNumberSetting = null; private int sliderStartX = 0; @@ -109,10 +107,6 @@ private void initializeModules() { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - if(Theme.get("Rye") == null) { - Theme.init(); - } - hoveredTooltip = null; for(Map.Entry> entry : categorizedModules.entrySet()) { @@ -170,9 +164,8 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { } if(module.isEnabled()) { - Theme currentTheme = Theme.getCurrentTheme(); - int primaryColor = currentTheme.getPrimaryColorInt(); - int secondaryColor = currentTheme.getSecondaryColorInt(); + int primaryColor = Theme.COLOR$1; + int secondaryColor = Theme.COLOR$2; primaryColor = primaryColor | 0xFF000000; secondaryColor = secondaryColor | 0xFF000000; @@ -302,7 +295,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { int filledWidth = (int) (sliderWidth * percentage); if(filledWidth > 0) { - RenderUtility.drawRoundedRect(context, sliderX, sliderY, filledWidth, sliderHeight, new Vector4f(2, 2, 2, 2), Theme.getCurrentTheme().getPrimaryColorInt()); + RenderUtility.drawRoundedRect(context, sliderX, sliderY, filledWidth, sliderHeight, new Vector4f(2, 2, 2, 2), Theme.COLOR$1); } int knobSize = 10; @@ -378,7 +371,8 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { dropdownWidth - 4, optionHeight - 4, new Vector4f(3, 3, 3, 3), - Theme.getCurrentTheme().getPrimaryColorInt()); + Theme.COLOR$1 + ); int checkboxSize = 8; int checkboxX = dropdownX + dropdownWidth - checkboxSize - 5; diff --git a/src/client/java/dev/thoq/utilities/misc/ChatUtility.java b/src/client/java/dev/thoq/utilities/misc/ChatUtility.java index 027e17c..390dcf7 100644 --- a/src/client/java/dev/thoq/utilities/misc/ChatUtility.java +++ b/src/client/java/dev/thoq/utilities/misc/ChatUtility.java @@ -27,6 +27,7 @@ @SuppressWarnings("unused") public class ChatUtility { private static final MinecraftClient mc = MinecraftClient.getInstance(); + private static final String RYE = "§5Rye§r"; /** * Sends a formatted message to the player @@ -36,17 +37,17 @@ public class ChatUtility { */ public static void sendMessage(String message, Formatting formatting) { if(mc.player != null) { + String newMessage = String.format("%s %s", RYE, message.replace("»", "§0»")); MutableText text = Text.literal(message).setStyle(Style.EMPTY.withColor(formatting)); mc.player.sendMessage(text, false); } } - public static void sendDebug(String message) { boolean debug = RyeClient.INSTANCE.getModuleRepository().getModule(DebugModule.class).isEnabled(); if(mc.player != null && debug) { - MutableText text = Text.literal("DEBUG >> " + message); + MutableText text = Text.literal("Debug » " + message); mc.player.sendMessage(text, false); } } @@ -66,7 +67,7 @@ public static void sendMessage(String message) { * @param message The error message */ public static void sendError(String message) { - sendMessage("Error: " + message, Formatting.RED); + sendMessage("Error » " + message, Formatting.RED); } /** @@ -107,7 +108,7 @@ public static void sendWarning(String message) { public static void sendPrefixedMessage(String prefix, String message, Formatting prefixFormatting, Formatting messageFormatting) { if(mc.player == null) return; - MutableText prefixText = Text.literal("[" + prefix + "] ").setStyle(Style.EMPTY.withColor(prefixFormatting)); + MutableText prefixText = Text.literal(RYE + " " + prefix + " » ").setStyle(Style.EMPTY.withColor(prefixFormatting)); MutableText messageText = Text.literal(message).setStyle(Style.EMPTY.withColor(messageFormatting)); mc.player.sendMessage(prefixText.append(messageText), false); } diff --git a/src/client/java/dev/thoq/utilities/misc/DoubleBlockPos.java b/src/client/java/dev/thoq/utilities/misc/DoubleBlockPos.java new file mode 100644 index 0000000..df7b19b --- /dev/null +++ b/src/client/java/dev/thoq/utilities/misc/DoubleBlockPos.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Rye Client 2024-2025. + * + * This file belongs to Rye Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/RyeClient/rye-v1.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Rye (and subsequently, its files) are all licensed under the MIT License. + * Rye should have come with a copy of the MIT License. + * If it did not, you may obtain a copy here: + * MIT License: https://opensource.org/license/mit + * + */ + +package dev.thoq.utilities.misc; + +import net.minecraft.util.math.BlockPos; + +public record DoubleBlockPos(double x, double y, double z) { + + public BlockPos toBlockPos() { + return new BlockPos((int) x, (int) y, (int) z); + } +} \ No newline at end of file diff --git a/src/client/java/dev/thoq/utilities/misc/RyeConstants.java b/src/client/java/dev/thoq/utilities/misc/RyeConstants.java index ea50f70..f43cfa6 100644 --- a/src/client/java/dev/thoq/utilities/misc/RyeConstants.java +++ b/src/client/java/dev/thoq/utilities/misc/RyeConstants.java @@ -18,7 +18,7 @@ public class RyeConstants { public static final String NAME = "Rye"; - public static final String VERSION = "0.1.27"; + public static final String VERSION = "0.1"; public static final String KIND = "Beta"; public static final String BUILD_NUMBER = "070225.5"; } diff --git a/src/client/java/dev/thoq/utilities/player/MoveUtility.java b/src/client/java/dev/thoq/utilities/player/MoveUtility.java index f74b5dd..e0d90d4 100644 --- a/src/client/java/dev/thoq/utilities/player/MoveUtility.java +++ b/src/client/java/dev/thoq/utilities/player/MoveUtility.java @@ -217,4 +217,23 @@ public static double getVanillaPlayerSpeed() { public static double getVanillaPlayerSprintSpeed() { return VANILLA_PLAYER_SPRINT_SPEED; } + + /** + * Calculates the square of the horizontal speed of the player. + * The computation is based on the player's velocity along the X and Z axes. + * If the player instance is null, the method will return 0.0. + * + * @return The squared horizontal speed of the player, or 0.0 if the player is not present. + */ + public static double getSpeed() { + MinecraftClient mc = MinecraftClient.getInstance(); + ClientPlayerEntity player = mc.player; + + if(player == null) return 0.0; + + double motionX = player.getVelocity().x; + double motionZ = player.getVelocity().z; + + return motionX * motionX + motionZ * motionZ; + } } diff --git a/src/client/java/dev/thoq/utilities/player/PlayerUtility.java b/src/client/java/dev/thoq/utilities/player/PlayerUtility.java index 724b9f7..e7bcf61 100644 --- a/src/client/java/dev/thoq/utilities/player/PlayerUtility.java +++ b/src/client/java/dev/thoq/utilities/player/PlayerUtility.java @@ -16,12 +16,16 @@ package dev.thoq.utilities.player; +import dev.thoq.utilities.misc.DoubleBlockPos; +import net.minecraft.block.AirBlock; +import net.minecraft.block.Block; import net.minecraft.client.MinecraftClient; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.math.BlockPos; public class PlayerUtility { - public static void applyDamage(MinecraftClient mc, int height) { + public void applyDamage(MinecraftClient mc, int height) { if(mc.player == null || mc.getNetworkHandler() == null) return; double x = mc.player.getX(); @@ -35,4 +39,30 @@ public static void applyDamage(MinecraftClient mc, int height) { mc.getNetworkHandler().sendPacket(new PlayerMoveC2SPacket.Full(x, baseY + height, z, yaw, pitch, onGround, horizontalCollision)); mc.getNetworkHandler().sendPacket(new PlayerMoveC2SPacket.Full(x, baseY, z, yaw, pitch, false, horizontalCollision)); } + + /** + * @return true if the player is over void, false otherwise + * @author slqnt + * @since 0.1 + */ + public boolean isOverVoid() { + MinecraftClient mc = MinecraftClient.getInstance(); + + if(mc.player == null) return false; + if(mc.world == null) return false; + + if(!mc.player.isOnGround()) { + for(double y = mc.player.getPos().y - 1; y >= 0.0; y--) { + BlockPos blockPos = new DoubleBlockPos(mc.player.getPos().x, y, mc.player.getPos().z).toBlockPos(); + Block block = mc.world.getBlockState(blockPos).getBlock(); + + if(!(block instanceof AirBlock)) + return false; + } + + return true; + } + + return false; + } } diff --git a/src/client/java/dev/thoq/utilities/render/RenderUtility.java b/src/client/java/dev/thoq/utilities/render/RenderUtility.java index 60edb13..7903456 100644 --- a/src/client/java/dev/thoq/utilities/render/RenderUtility.java +++ b/src/client/java/dev/thoq/utilities/render/RenderUtility.java @@ -29,6 +29,25 @@ public class RenderUtility { private static final MinecraftClient MC = MinecraftClient.getInstance(); + /** + * Represents the four corners of a rectangle. + *

+ * This enum is used to specify which corner of a rectangle is being targeted + * for rendering or calculation tasks in graphical operations. The enumeration + * includes: + * - TOP_LEFT: The top-left corner of a rectangle. + * - TOP_RIGHT: The top-right corner of a rectangle. + * - BOTTOM_RIGHT: The bottom-right corner of a rectangle. + * - BOTTOM_LEFT: The bottom-left corner of a rectangle. + *

+ * It is typically utilized in graphical rendering methods to define or modify + * specific corners of a rounded rectangle, such as drawing filled or outlined + * corners, calculating pixel coverage, or rendering individual corner details. + */ + private enum CornerType { + TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT + } + /** * Draws a filled rounded rectangle with the specified position, dimensions, corner radius, and color. * @@ -270,22 +289,76 @@ public static void drawRoundedRectOutline(DrawContext context, float x, float y, } public static void drawGradientRoundedRect(DrawContext context, int x, int y, int width, int height, Vector4f radius, int colorLeft, int colorRight) { - for (int i = 0; i < width; i++) { - float factor = (float) i / width; + int cornerSize = (int) Math.max(Math.max(radius.x, radius.y), Math.max(radius.z, radius.w)); + int segments = Math.max(width / 2, 1); + + for(int i = 0; i < segments; i++) { + int segmentStartX = x + (i * width) / segments; + int segmentEndX = x + ((i + 1) * width) / segments; + int segmentWidth = segmentEndX - segmentStartX; + + float factor = segments > 1 ? (float) i / (segments - 1) : 0.0f; int interpolatedColor = ColorUtility.interpolateColor(colorLeft, colorRight, factor); - Vector4f columnRadius = new Vector4f(0, 0, 0, 0); - - if (i == 0) { - columnRadius.x = radius.x; - columnRadius.w = radius.w; + context.fill(segmentStartX, y + (int) Math.max(radius.x, radius.y), + segmentEndX, y + height - (int) Math.max(radius.z, radius.w), interpolatedColor); + } + + for(int i = 0; i < segments; i++) { + int segmentStartX = x + (i * width) / segments; + int segmentEndX = x + ((i + 1) * width) / segments; + + float factor = segments > 1 ? (float) i / (segments - 1) : 0.0f; + int interpolatedColor = ColorUtility.interpolateColor(colorLeft, colorRight, factor); + + int topStartX = Math.max(segmentStartX, x + (int) radius.x); + int topEndX = Math.min(segmentEndX, x + width - (int) radius.y); + if(topStartX < topEndX) { + context.fill(topStartX, y, topEndX, y + (int) Math.max(radius.x, radius.y), interpolatedColor); } - if (i == width - 1) { - columnRadius.y = radius.y; - columnRadius.z = radius.z; + + int bottomStartX = Math.max(segmentStartX, x + (int) radius.w); + int bottomEndX = Math.min(segmentEndX, x + width - (int) radius.z); + if(bottomStartX < bottomEndX) { + context.fill(bottomStartX, y + height - (int) Math.max(radius.z, radius.w), + bottomEndX, y + height, interpolatedColor); } + } + + drawGradientCorner(context, x, y, (int) radius.x, colorLeft, CornerType.TOP_LEFT); + drawGradientCorner(context, x + width - (int) radius.y, y, (int) radius.y, colorRight, CornerType.TOP_RIGHT); + drawGradientCorner(context, x + width - (int) radius.z, y + height - (int) radius.z, (int) radius.z, colorRight, CornerType.BOTTOM_RIGHT); + drawGradientCorner(context, x, y + height - (int) radius.w, (int) radius.w, colorLeft, CornerType.BOTTOM_LEFT); + } + + /** + * Draws a single corner with anti-aliasing and the specified color. + * This method uses the same anti-aliasing technique as your existing drawCorner method. + */ + private static void drawGradientCorner(DrawContext context, int x, int y, int radius, int color, CornerType corner) { + if(radius <= 0) return; + + int baseAlpha = (color >> 24) & 0xFF; + int red = (color >> 16) & 0xFF; + int green = (color >> 8) & 0xFF; + int blue = color & 0xFF; + + for(int py = 0; py < radius; py++) { + for(int px = 0; px < radius; px++) { + float coverage = getPixelCoverage(px, py, radius, corner); + + if(coverage > 0) { + int alpha = (int) (baseAlpha * coverage); + if(alpha > 0) { + int pixelColor = (alpha << 24) | (red << 16) | (green << 8) | blue; - drawRoundedRect(context, x + i, y, 1, height, columnRadius, interpolatedColor); + int drawX = x + (corner == CornerType.TOP_RIGHT || corner == CornerType.BOTTOM_RIGHT ? radius - px - 1 : px); + int drawY = y + (corner == CornerType.BOTTOM_LEFT || corner == CornerType.BOTTOM_RIGHT ? radius - py - 1 : py); + + context.fill(drawX, drawY, drawX + 1, drawY + 1, pixelColor); + } + } + } } } @@ -293,7 +366,30 @@ public static void drawRect(DrawContext context, float x, float y, float width, context.fill((int) x, (int) y, (int) (x + width), (int) (y + height), color); } - private enum CornerType { - TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT + /** + * Draws a line between two points with specified thickness and color. + * + * @param context The {@code DrawContext} used for rendering the line. + * @param x The x-coordinate of the starting point of the line. + * @param y The y-coordinate of the starting point of the line. + * @param toX The*/ + public static void drawLine( + DrawContext context, + int x, + int y, + int toX, + int toY, + float thickness, + int color + ) { + ExtendedDrawContext.drawLine( + context, + x, + y, + toX, + toY, + thickness, + new Color(color) + ); } } \ No newline at end of file diff --git a/src/client/java/dev/thoq/utilities/render/TextRendererUtility.java b/src/client/java/dev/thoq/utilities/render/TextRendererUtility.java index bcc17d7..6d70f40 100644 --- a/src/client/java/dev/thoq/utilities/render/TextRendererUtility.java +++ b/src/client/java/dev/thoq/utilities/render/TextRendererUtility.java @@ -24,6 +24,7 @@ public class TextRendererUtility { static TextRenderer renderer = FontManager.getFont("sf_pro_rounded_regular", 11); + static TextRenderer rendererMd = FontManager.getFont("sf_pro_rounded_regular", 15); static TextRenderer rendererXl = FontManager.getFont("sf_pro_rounded_regular", 50); /** @@ -82,6 +83,34 @@ public static void renderXlText( ); } + /** + * Renders a medium (Md) text string on the screen at the specified position with a designated color and optional shadow. + * + * @param context The drawing context used for rendering the text. + * @param text The text to be rendered. + * @param color The color of the text, specified as an enum value from {@link Colors}. + * @param posX The X-coordinate where the text should be rendered. + * @param posY The Y-coordinate where the text should be rendered. + * @param shadow A boolean value indicating whether to render the text with a shadow effect. + */ + public static void renderMdText( + DrawContext context, + String text, + Colors color, + int posX, + int posY, + boolean shadow + ) { + context.drawText( + rendererMd, + text, + posX, + posY, + ColorUtility.getColor(color), + shadow + ); + } + /** * Renders a text string on the screen at the specified position with a designated color and optional shadow. * @@ -138,4 +167,22 @@ public static int getXlTextWidth(String text) { public static int getTextHeight() { return renderer.fontHeight; } + + /** + * Retrieves the height of the extra-large text font used by the renderer. + * + * @return The height of the extra-large font in pixels. + */ + public static int getXlTextHeight() { + return rendererXl.fontHeight; + } + + /** + * Retrieves the height of the medium (Md) text font used by the renderer. + * + * @return The height of the medium font in pixels. + */ + public static int getMdTextHeight() { + return rendererMd.fontHeight; + } } diff --git a/src/client/java/dev/thoq/utilities/render/Theme.java b/src/client/java/dev/thoq/utilities/render/Theme.java index 4d9b7da..64039b3 100644 --- a/src/client/java/dev/thoq/utilities/render/Theme.java +++ b/src/client/java/dev/thoq/utilities/render/Theme.java @@ -16,137 +16,15 @@ package dev.thoq.utilities.render; -import dev.thoq.config.setting.Setting; -import dev.thoq.config.setting.impl.ModeSetting; -import dev.thoq.module.Module; -import dev.thoq.module.ModuleRepository; -import dev.thoq.utilities.types.Pair; - -import java.awt.*; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings({"FieldCanBeLocal", "unused"}) -public enum Theme { - RYE("Rye", new Color(92, 58, 220), new Color(100, 88, 147)), - PINK_LEMONADE("Pink Lemonade", new Color(255, 105, 180), new Color(255, 182, 193)), - SORBET("Sorbet", new Color(250, 171, 189), new Color(173, 81, 102)); - - private static final Map themeMap = new HashMap<>(); - private static Theme currentTheme = RYE; - - private final String name; - private final Pair colors; - - Theme(String name, Color color, Color colorAlternative) { - this.name = name; - System.out.println("Registering theme: " + name); - colors = Pair.of(color, colorAlternative); - } - - public static void init() { - Arrays.stream(values()).forEach(theme -> themeMap.put(theme.name, theme)); - } - - public Pair getColors() { - return colors; - } - - public String getName() { - return name; - } - - public Color getPrimaryColor() { - return colors.getFirst(); - } - - public Color getSecondaryColor() { - return colors.getSecond(); - } - - public int getPrimaryColorInt() { - return ColorUtility.getIntFromColor(getPrimaryColor()); - } - - public int getSecondaryColorInt() { - return ColorUtility.getIntFromColor(getSecondaryColor()); - } - - public static Pair getThemeColors(String name) { - return get(name).getColors(); - } - - public static Theme get(String name) { - return themeMap.get(name); - } - - public static Theme getCurrentTheme() { - try { - ModuleRepository repository = ModuleRepository.getInstance(); - Module hudModule = repository.getModuleByName("HUD"); - if(hudModule == null) - throw new IllegalStateException("HUD module either found or not loaded"); - - for(Setting setting : hudModule.getSettings()) { - if(setting.getName().equals("Theme") && setting instanceof ModeSetting themeSetting) { - String currentThemeName = themeSetting.getValue(); - if(currentThemeName == null) { - currentThemeName = RYE.getName(); - currentTheme = RYE; - } - - Theme theme = get(currentThemeName); - if(theme == null) { - theme = RYE; - } - - currentTheme = theme; - return currentTheme; - } - } - } catch(Exception ignored) { - } - - return currentTheme; - } - - public static void setCurrentTheme(Theme theme) { - currentTheme = theme; - } - - public static void setCurrentTheme(String themeName) { - Theme theme = get(themeName); - if(theme != null) { - currentTheme = theme; - } - } - - public static Color interpolateColor(Color color1, Color color2, float factor) { - factor = Math.max(0.0f, Math.min(1.0f, factor)); - - int r = (int) (color1.getRed() + factor * (color2.getRed() - color1.getRed())); - int g = (int) (color1.getGreen() + factor * (color2.getGreen() - color1.getGreen())); - int b = (int) (color1.getBlue() + factor * (color2.getBlue() - color1.getBlue())); - int a = (int) (color1.getAlpha() + factor * (color2.getAlpha() - color1.getAlpha())); - - return new Color(r, g, b, a); - } - - public static int interpolateColorInt(Color color1, Color color2, float factor) { - return ColorUtility.getIntFromColor(interpolateColor(color1, color2, factor)); - } - - public static Color getInterpolatedThemeColor(float factor) { - Theme theme = getCurrentTheme(); - return interpolateColor(theme.getPrimaryColor(), theme.getSecondaryColor(), factor); - } - - public static int getInterpolatedThemeColorInt(float factor) { - return ColorUtility.getIntFromColor(getInterpolatedThemeColor(factor)); - } - - public static String[] getThemeNames() { - return Arrays.stream(values()).map(Theme::getName).toArray(String[]::new); +public class Theme { + public static int COLOR$1 = 0xFFB734EB; + public static int COLOR$2 = 0xFF8334EB; + + public static int getInterpolatedColors(float factor) { + return ColorUtility.interpolateColor( + COLOR$1, + COLOR$2, + factor + ); } } \ No newline at end of file diff --git a/src/client/java/dev/thoq/utilities/render/ThemeUtility.java b/src/client/java/dev/thoq/utilities/render/ThemeUtility.java index b12b8a7..b98d9e0 100644 --- a/src/client/java/dev/thoq/utilities/render/ThemeUtility.java +++ b/src/client/java/dev/thoq/utilities/render/ThemeUtility.java @@ -21,7 +21,7 @@ @SuppressWarnings("unused") public class ThemeUtility { private static Color themeColorFirst = Color.PINK; - private static Color themeColorSecond = Color.GREEN; + private static Color themeColorSecond = Color.BLUE; public static Color getThemeColorFirst() { return themeColorFirst; diff --git a/src/main/resources/assets/rye/images/rye_logo_white.png b/src/main/resources/assets/rye/images/rye_logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..f2c7d6c6cfb33a413ffa3d54185a4c9703216753 GIT binary patch literal 50393 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 Y=l3_xyD=`mhWwxTFyikeA4vB72R3i!N&o-= literal 0 HcmV?d00001