From 95fb108c6fe06046215c08cad1868cf5762c4f0b Mon Sep 17 00:00:00 2001 From: Tristan Date: Sun, 6 Jul 2025 04:20:26 -0400 Subject: [PATCH 01/15] fix(version) --- src/client/java/works/alya/utilities/misc/AlyaConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/java/works/alya/utilities/misc/AlyaConstants.java b/src/client/java/works/alya/utilities/misc/AlyaConstants.java index 6c140d2..8914253 100644 --- a/src/client/java/works/alya/utilities/misc/AlyaConstants.java +++ b/src/client/java/works/alya/utilities/misc/AlyaConstants.java @@ -18,7 +18,7 @@ public class AlyaConstants { public static final String NAME = "Alya"; - public static final String VERSION = "6.0"; + public static final String VERSION = "0.1"; public static final String KIND = "Beta"; public static final String BUILD_NUMBER = "07052025.6"; } From d19b4f9c1333a753d6b20c60d9615f3b3c65e3d8 Mon Sep 17 00:00:00 2001 From: Tristan Date: Sun, 6 Jul 2025 18:31:04 -0400 Subject: [PATCH 02/15] feat(kitty) feat(ncp fly): not complete --- .../alya/mixin/client/ui/ScreenMixin.java | 2 +- .../client/ui/WatermarkTitleScreenMixin.java | 36 ---- .../module/impl/movement/ScaffoldModule.java | 5 +- .../impl/movement/flight/FlightModule.java | 4 +- .../impl/movement/flight/ncp/NCPFlight.java | 72 +++++++ .../utilities/misc/BackgroundUtility.java | 183 +++++++++++++++++- .../resources/assets/alya/images/kitty.png | Bin 0 -> 118583 bytes 7 files changed, 255 insertions(+), 47 deletions(-) create mode 100644 src/client/java/works/alya/module/impl/movement/flight/ncp/NCPFlight.java create mode 100644 src/main/resources/assets/alya/images/kitty.png diff --git a/src/client/java/works/alya/mixin/client/ui/ScreenMixin.java b/src/client/java/works/alya/mixin/client/ui/ScreenMixin.java index 561b86a..a8b3646 100644 --- a/src/client/java/works/alya/mixin/client/ui/ScreenMixin.java +++ b/src/client/java/works/alya/mixin/client/ui/ScreenMixin.java @@ -31,7 +31,7 @@ public class ScreenMixin { @Inject(method = "renderPanoramaBackground", at = @At("HEAD"), cancellable = true) private void interceptPanoramaBackground(DrawContext context, float deltaTicks, CallbackInfo ci) { if(!Settings.SHOW_PANORAMA) { - BackgroundUtility.drawBackground(context); + BackgroundUtility.drawStarField(context); ci.cancel(); } diff --git a/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java b/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java index db7ce49..6ba9383 100644 --- a/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java +++ b/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java @@ -91,42 +91,6 @@ private void disableSplashText(CallbackInfo ci) { private void cancelSplashTextRendering(SplashTextRenderer splashTextRenderer, DrawContext context, int width, net.minecraft.client.font.TextRenderer textRenderer, float alpha) { } - @Inject(method = "init", at = @At("TAIL")) - private void centerButtons(CallbackInfo ci) { - TitleScreen screen = (TitleScreen) (Object) this; - - int screenWidth = screen.width; - int screenHeight = screen.height; - int centerX = screenWidth / 2; - int centerY = screenHeight / 2; - - List buttons = new ArrayList<>(); - for(Element element : screen.children()) { - if(element instanceof ButtonWidget button) { - buttons.add(button); - } - } - - if(!buttons.isEmpty()) { - int totalHeight = 0; - for(int i = 0; i < buttons.size(); i++) { - totalHeight += buttons.get(i).getHeight(); - if(i < buttons.size() - 1) { - totalHeight += 24; - } - } - - int currentY = centerY - (totalHeight / 2); - for(ButtonWidget button : buttons) { - int buttonWidth = button.getWidth(); - int newX = centerX - (buttonWidth / 2); - - button.setPosition(newX, currentY); - currentY += button.getHeight() + 24; - } - } - } - @Inject(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/AccessibilityOnboardingButtons;createLanguageButton(ILnet/minecraft/client/gui/widget/ButtonWidget$PressAction;Z)Lnet/minecraft/client/gui/widget/TextIconButtonWidget;", shift = At.Shift.AFTER), cancellable = true) private void skipLanguageButtonSetup(CallbackInfo ci) { ci.cancel(); diff --git a/src/client/java/works/alya/module/impl/movement/ScaffoldModule.java b/src/client/java/works/alya/module/impl/movement/ScaffoldModule.java index 3e76451..013088e 100644 --- a/src/client/java/works/alya/module/impl/movement/ScaffoldModule.java +++ b/src/client/java/works/alya/module/impl/movement/ScaffoldModule.java @@ -311,10 +311,11 @@ private void handleTower() { break; case "Verus": if(mc.player.isOnGround()) { - MoveUtility.setMotionY(-0.1f); + Vec3d position = mc.player.getPos(); + mc.player.setPosition(position.x, position.y - 0.1, position.z); mc.player.jump(); } else { - MoveUtility.setMotionY(1f); + MoveUtility.setMotionY(1.0f); } break; case "Vulcan": diff --git a/src/client/java/works/alya/module/impl/movement/flight/FlightModule.java b/src/client/java/works/alya/module/impl/movement/flight/FlightModule.java index a345401..d611440 100644 --- a/src/client/java/works/alya/module/impl/movement/flight/FlightModule.java +++ b/src/client/java/works/alya/module/impl/movement/flight/FlightModule.java @@ -18,6 +18,7 @@ import works.alya.module.Module; import works.alya.module.ModuleCategory; +import works.alya.module.impl.movement.flight.ncp.NCPFlight; import works.alya.module.impl.movement.flight.vanilla.CreativeFlight; import works.alya.module.impl.movement.flight.vanilla.NormalFlight; import works.alya.module.impl.movement.flight.verus.VerusDamageFly; @@ -35,7 +36,8 @@ public FlightModule() { new CreativeFlight(this), new VerusPacketFlight(this), new VerusDamageFly(this), - new VerusGlideFly(this) + new VerusGlideFly(this), + new NCPFlight(this) ); } diff --git a/src/client/java/works/alya/module/impl/movement/flight/ncp/NCPFlight.java b/src/client/java/works/alya/module/impl/movement/flight/ncp/NCPFlight.java new file mode 100644 index 0000000..800a9c0 --- /dev/null +++ b/src/client/java/works/alya/module/impl/movement/flight/ncp/NCPFlight.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya 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 works.alya.module.impl.movement.flight.ncp; + +import net.minecraft.network.packet.s2c.play.MoveMinecartAlongTrackS2CPacket; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import works.alya.event.IEventListener; +import works.alya.event.impl.MotionEvent; +import works.alya.module.Module; +import works.alya.module.SubModule; +import works.alya.utilities.misc.ChatUtility; +import works.alya.utilities.player.MoveUtility; + +public class NCPFlight extends SubModule { + static boolean messageSent = false; + static boolean clipped = false; + + public NCPFlight(Module parent) { + super("NCP", parent); + } + + private final IEventListener motionEvent = event -> { + if(mc.player == null) return; + if(mc.world == null) return; + if(!event.isPre()) return; + + Vec3d pos = mc.player.getPos(); + BlockPos blockAbovePlayer = new BlockPos((int)pos.x, (int)(pos.y + mc.player.getHeight() + 0.5), (int)pos.z); + boolean isBlockAbovePlayer = !mc.world.getBlockState(blockAbovePlayer).isAir(); + + if(true) { + if(!clipped) { + mc.player.setPosition(pos.x, pos.y + 0.1, pos.z); + MoveUtility.setMotionY(0.2); + clipped = true; + } + } else { + if(!messageSent) { + ChatUtility.sendWarning("Please be under a block before enabling this fly!"); + messageSent = true; + } + } + + if(clipped) { + MoveUtility.setSpeed(2.0f, true); + MoveUtility.setMotionY(-0.2); + } + }; + + @Override + public void reset() { + super.reset(); + + messageSent = false; + clipped = false; + } +} diff --git a/src/client/java/works/alya/utilities/misc/BackgroundUtility.java b/src/client/java/works/alya/utilities/misc/BackgroundUtility.java index e10cf26..4116ed6 100644 --- a/src/client/java/works/alya/utilities/misc/BackgroundUtility.java +++ b/src/client/java/works/alya/utilities/misc/BackgroundUtility.java @@ -16,25 +16,194 @@ package works.alya.utilities.misc; +import works.alya.utilities.render.ColorUtility; import works.alya.utilities.render.RenderUtility; -import works.alya.utilities.render.Theme; import net.minecraft.client.gui.DrawContext; -import org.joml.Vector4f; +import net.minecraft.util.Identifier; + +import java.util.Random; public class BackgroundUtility { - public static void drawBackground(DrawContext context) { + private static final int MAX_STARS = 200; + private static final Star[] stars = new Star[MAX_STARS]; + private static final Random random = new Random(); + private static boolean initialized = false; + private static int lastWidth = 0; + private static int lastHeight = 0; + + private static final Identifier KITTY_TEXTURE = Identifier.of("alya", "images/kitty.png"); + private static final FloatingKitty kitty = new FloatingKitty(); + + private static class Star { + float x, y; + float alpha; + float fadeSpeed; + boolean fadingIn; + int size; + + Star(float x, float y) { + this.x = x; + this.y = y; + this.alpha = 0.0f; + this.fadeSpeed = 0.01f + random.nextFloat() * 0.02f; + this.fadingIn = true; + this.size = 1; + } + + void update() { + if(fadingIn) { + alpha += fadeSpeed; + if(alpha >= 1.0f) { + alpha = 1.0f; + fadingIn = false; + } + } else { + alpha -= fadeSpeed; + if(alpha <= 0.0f) { + alpha = 0.0f; + fadingIn = true; + } + } + } + + void render(DrawContext context) { + if(alpha > 0.0f) { + int whiteColor = 0xFFFFFF; + int alphaValue = (int) (alpha * 255); + int colorWithAlpha = (alphaValue << 24) | whiteColor; + RenderUtility.drawRect(context, x, y, size, size, colorWithAlpha); + } + } + + void resetPosition(int screenWidth, int screenHeight) { + this.x = random.nextFloat() * screenWidth; + this.y = random.nextFloat() * screenHeight; + this.alpha = 0.0f; + this.fadingIn = true; + this.fadeSpeed = 0.01f + random.nextFloat() * 0.02f; + } + } + + private static class FloatingKitty { + double x, y; + double velocityX, velocityY; + int width = 128; + int height = 128; + boolean initialized = false; + + void initialize(int screenWidth, int screenHeight) { + this.x = random.nextDouble() * (screenWidth - width); + this.y = random.nextDouble() * (screenHeight - height); + this.velocityX = (random.nextDouble() - 0.5) * 0.8; + this.velocityY = (random.nextDouble() - 0.5) * 0.8; + this.initialized = true; + } + + void update(int screenWidth, int screenHeight) { + if(!initialized) { + initialize(screenWidth, screenHeight); + return; + } + + x += velocityX; + y += velocityY; + + if(x <= 0 || x >= screenWidth - width) { + velocityX = -velocityX; + x = Math.max(0, Math.min(screenWidth - width, x)); + } + + if(y <= 0 || y >= screenHeight - height) { + velocityY = -velocityY; + y = Math.max(0, Math.min(screenHeight - height, y)); + } + + if(random.nextDouble() < 0.003) { + velocityX += (random.nextDouble() - 0.5) * 0.1; + velocityY += (random.nextDouble() - 0.5) * 0.1; + + velocityX = Math.max(-1.2, Math.min(1.2, velocityX)); + velocityY = Math.max(-1.2, Math.min(1.2, velocityY)); + } + } + + void render(DrawContext context) { + if(initialized) { + RenderUtility.drawImage( + KITTY_TEXTURE, + (int) Math.round(x), + (int) Math.round(y), + width, + height, + width, + height, + context + ); + } + } + + void resetPosition(int screenWidth, int screenHeight) { + initialize(screenWidth, screenHeight); + } + } + + public static void initializeStars(int screenWidth, int screenHeight) { + for(int i = 0; i < MAX_STARS; i++) { + float x = random.nextFloat() * screenWidth; + float y = random.nextFloat() * screenHeight; + stars[i] = new Star(x, y); + + if(random.nextBoolean()) { + stars[i].alpha = random.nextFloat(); + stars[i].fadingIn = random.nextBoolean(); + } + } + initialized = true; + lastWidth = screenWidth; + lastHeight = screenHeight; + kitty.resetPosition(screenWidth, screenHeight); + } + + public static void updateStars(int screenWidth, int screenHeight) { + if(!initialized || screenWidth != lastWidth || screenHeight != lastHeight) { + initializeStars(screenWidth, screenHeight); + return; + } + + for(Star star : stars) { + star.update(); + + if(random.nextFloat() < 0.001f) { + star.resetPosition(screenWidth, screenHeight); + } + } + + kitty.update(screenWidth, screenHeight); + } + + public static void renderStars(DrawContext context) { + if(!initialized) return; + + for(Star star : stars) { + star.render(context); + } + } + + public static void drawStarField(DrawContext context) { int width = context.getScaledWindowWidth(); int height = context.getScaledWindowHeight(); - RenderUtility.drawGradientRoundedRect( + RenderUtility.drawRect( context, 0, 0, width, height, - new Vector4f(0, 0, 0, 0), - Theme.COLOR$1, - Theme.COLOR$2 + ColorUtility.getColor(ColorUtility.Colors.BLACK) ); + + updateStars(width, height); + renderStars(context); + kitty.render(context); } } \ No newline at end of file diff --git a/src/main/resources/assets/alya/images/kitty.png b/src/main/resources/assets/alya/images/kitty.png new file mode 100644 index 0000000000000000000000000000000000000000..15366c7afe672ffcd0b500c3fae1abf44b22aa8f GIT binary patch literal 118583 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

mh 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

oP;BJX&~`>`WGT1kZ-CrKR-PP26Lqd{ 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 e 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 Yv`X9>zGe7{12r&sy85}Sb4q9e0AZX{fdBvi literal 0 HcmV?d00001 From 70542e3b68314ee6b7a8ef96432c551603d73fd8 Mon Sep 17 00:00:00 2001 From: Tristan Date: Mon, 7 Jul 2025 04:10:43 -0400 Subject: [PATCH 03/15] feat(maybe fixed the tomefoolery) --- .../client/ui/WatermarkTitleScreenMixin.java | 4 - .../impl/visual/SpeedMonitorModule.java | 76 ++++++++++++------- .../utilities/misc/BackgroundUtility.java | 6 +- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java b/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java index 6ba9383..08b08cb 100644 --- a/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java +++ b/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java @@ -23,7 +23,6 @@ import net.minecraft.client.gui.*; import net.minecraft.client.gui.screen.SplashTextRenderer; import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.client.gui.widget.ButtonWidget; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -32,9 +31,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.List; - @Mixin(TitleScreen.class) public class WatermarkTitleScreenMixin { diff --git a/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java b/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java index e0aa15c..844dcea 100644 --- a/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java +++ b/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java @@ -32,12 +32,13 @@ @SuppressWarnings("SameParameterValue") public class SpeedMonitorModule extends Module { - private final double[] bpsHistory = new double[1000]; + private final double[] bpsHistory = new double[200]; private int historyIndex = 0; private int historySize = 0; private final DragUtility dragUtility = new DragUtility(4, 60); private static final int WHITE_COLOR = ColorUtility.getColor(ColorUtility.Colors.WHITE); - private static final int MAX_HISTORY_SIZE = 1000; + private static final int MAX_HISTORY_SIZE = 200; + private static final int MAX_RENDER_POINTS = 100; public SpeedMonitorModule() { super("SpeedMonitor", "Speed Monitor", "Shows the average player speed and a graph", ModuleCategory.VISUAL); @@ -70,23 +71,16 @@ public SpeedMonitorModule() { String currentBps = AlyaClient.getBps(); double bpsValue = Double.parseDouble(currentBps); - int maxHistorySize = 1000; - bpsHistory[historyIndex] = bpsValue; - historyIndex = (historyIndex + 1) % maxHistorySize; - if(historySize < maxHistorySize) { - historySize++; - } + updateSpeedHistory(bpsValue); int contentX = xPosition + (padding - 1); int contentY = yPosition + (padding * 2) + 2; int graphY; int graphHeight = 50 - padding; int graphWidth = rectWidth - (padding * 2) + 2; - 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); String averageBps = AlyaClient.getBps(); String averageText = String.format("Average: %.1f", Double.parseDouble(averageBps)); @@ -128,37 +122,55 @@ public SpeedMonitorModule() { 0x44000000 ); - if(historySize > 1) { - double maxBps = 100; + renderSpeedGraph(event, contentX, graphY, graphWidth, graphHeight); + }; + + private void updateSpeedHistory(double bpsValue) { + bpsHistory[historyIndex] = bpsValue; + historyIndex = (historyIndex + 1) % MAX_HISTORY_SIZE; + if(historySize < MAX_HISTORY_SIZE) { + historySize++; + } + } + + private void renderSpeedGraph(Render2DEvent event, int contentX, int graphY, int graphWidth, int graphHeight) { + if(historySize <= 1) return; - int graphWidthMinus1 = graphWidth - 1; - int historySizeMinus1 = historySize - 1; - int startIndex = (historyIndex - historySize + MAX_HISTORY_SIZE) % MAX_HISTORY_SIZE; + double maxBps = 100; - for(int i = 1; i < historySize; i++) { - int prevIndex = (startIndex + i - 1) % MAX_HISTORY_SIZE; - int currIndex = (startIndex + i) % MAX_HISTORY_SIZE; + int renderPoints = Math.min(historySize, MAX_RENDER_POINTS); + int stepSize = Math.max(1, historySize / renderPoints); + int graphWidthMinus1 = graphWidth - 1; + int renderPointsMinus1 = renderPoints - 1; + int startIndex = (historyIndex - historySize + MAX_HISTORY_SIZE) % MAX_HISTORY_SIZE; - double prevBps = bpsHistory[prevIndex]; - double currBps = bpsHistory[currIndex]; + for(int i = 1; i < renderPoints; i++) { + int prevDataIndex = (startIndex + (i - 1) * stepSize) % MAX_HISTORY_SIZE; + int currDataIndex = (startIndex + i * stepSize) % MAX_HISTORY_SIZE; - int x1 = contentX + ((i - 1) * graphWidthMinus1) / historySizeMinus1; - int y1 = graphY + graphHeight - (int) (Math.min(prevBps, maxBps) * graphHeight / maxBps); - int x2 = contentX + (i * graphWidthMinus1) / historySizeMinus1; - int y2 = graphY + graphHeight - (int) (Math.min(currBps, maxBps) * graphHeight / maxBps); + double prevBps = bpsHistory[prevDataIndex]; + double currBps = bpsHistory[currDataIndex]; - y1 = Math.max(y1, graphY); - y2 = Math.max(y2, graphY); + int x1 = contentX + ((i - 1) * graphWidthMinus1) / renderPointsMinus1; + int y1 = graphY + graphHeight - (int) (Math.min(prevBps, maxBps) * graphHeight / maxBps); + int x2 = contentX + (i * graphWidthMinus1) / renderPointsMinus1; + int y2 = graphY + graphHeight - (int) (Math.min(currBps, maxBps) * graphHeight / maxBps); + y1 = Math.max(y1, graphY); + y2 = Math.max(y2, graphY); + y1 = Math.min(y1, graphY + graphHeight); + y2 = Math.min(y2, graphY + graphHeight); + + if(x1 != x2 || y1 != y2) { RenderUtility.drawLine( event.getContext(), x1, y1, x2, y2, - 2f, + 1.5f, WHITE_COLOR ); } } - }; + } private void handleMouseInput(int x, int y, int width, int height) { if(mc.mouse == null) return; @@ -181,4 +193,12 @@ private void handleMouseInput(int x, int y, int width, int height) { } } } + + @Override + protected void onDisable() { + historyIndex = 0; + historySize = 0; + + super.onDisable(); + } } \ No newline at end of file diff --git a/src/client/java/works/alya/utilities/misc/BackgroundUtility.java b/src/client/java/works/alya/utilities/misc/BackgroundUtility.java index 4116ed6..c53d89b 100644 --- a/src/client/java/works/alya/utilities/misc/BackgroundUtility.java +++ b/src/client/java/works/alya/utilities/misc/BackgroundUtility.java @@ -24,7 +24,7 @@ import java.util.Random; public class BackgroundUtility { - private static final int MAX_STARS = 200; + private static final int MAX_STARS = 1000; private static final Star[] stars = new Star[MAX_STARS]; private static final Random random = new Random(); private static boolean initialized = false; @@ -87,8 +87,8 @@ void resetPosition(int screenWidth, int screenHeight) { private static class FloatingKitty { double x, y; double velocityX, velocityY; - int width = 128; - int height = 128; + int width = 64; + int height = 64; boolean initialized = false; void initialize(int screenWidth, int screenHeight) { From be70d28d0c88b644d2f5e803cf3fb54b09982727 Mon Sep 17 00:00:00 2001 From: Tristan Date: Tue, 8 Jul 2025 03:15:31 -0400 Subject: [PATCH 04/15] fix(cgui looks less borked) --- .../impl/visual/clickgui/dropdown/DropDownClickGUI.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java b/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java index 270d3ef..806c2cf 100644 --- a/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java +++ b/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java @@ -214,9 +214,9 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { RenderUtility.drawGradientRoundedRect( context, - categoryX + 1, + categoryX, y, - PANEL_WIDTH - 2, + PANEL_WIDTH, MODULE_HEIGHT, moduleRadius, primaryColor, @@ -229,7 +229,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { if(shouldRoundBottom) { hoverRadius = new Vector4f(0f, CORNER_RADIUS,0f , CORNER_RADIUS); } - RenderUtility.drawRoundedRect(context, categoryX + 1, y, PANEL_WIDTH - 2, MODULE_HEIGHT, hoverRadius, HOVER_COLOR); + RenderUtility.drawRoundedRect(context, categoryX, y, PANEL_WIDTH, MODULE_HEIGHT, hoverRadius, HOVER_COLOR); } int textColor = module.isEnabled() ? @@ -813,4 +813,4 @@ private void renderGradientRoundedRect(DrawContext context, int x, int y, int wi public boolean shouldPause() { return false; } -} +} \ No newline at end of file From bde9cf01a8ad268b71a3edfc1a2be58e40629447 Mon Sep 17 00:00:00 2001 From: Tristan Date: Tue, 8 Jul 2025 16:54:20 -0400 Subject: [PATCH 05/15] add astolfo click gui --- .../impl/visual/SpeedMonitorModule.java | 4 +- .../impl/visual/clickgui/ClickGUIModule.java | 18 +- .../clickgui/astolfo/AstolfoClickGUI.java | 396 ++++++++++++++++++ .../clickgui/dropdown/DropDownClickGUI.java | 43 +- .../utilities/render/TextRendererUtility.java | 4 +- 5 files changed, 430 insertions(+), 35 deletions(-) create mode 100644 src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java diff --git a/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java b/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java index 844dcea..7841a87 100644 --- a/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java +++ b/src/client/java/works/alya/module/impl/visual/SpeedMonitorModule.java @@ -87,7 +87,7 @@ public SpeedMonitorModule() { TextRendererUtility.renderDynamicText( event.getContext(), "Speed", - ColorUtility.Colors.WHITE, + 0xFFFFFFFF, contentX + padding, contentY, false, @@ -101,7 +101,7 @@ public SpeedMonitorModule() { TextRendererUtility.renderDynamicText( event.getContext(), averageText, - ColorUtility.Colors.WHITE, + ColorUtility.getColor(ColorUtility.Colors.WHITE), averageTextX, contentY, false, diff --git a/src/client/java/works/alya/module/impl/visual/clickgui/ClickGUIModule.java b/src/client/java/works/alya/module/impl/visual/clickgui/ClickGUIModule.java index 0ee0334..80729de 100644 --- a/src/client/java/works/alya/module/impl/visual/clickgui/ClickGUIModule.java +++ b/src/client/java/works/alya/module/impl/visual/clickgui/ClickGUIModule.java @@ -19,14 +19,18 @@ import works.alya.AlyaClient; import works.alya.config.KeybindManager; import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.ModeSetting; import works.alya.module.Module; import works.alya.module.ModuleCategory; +import works.alya.module.impl.visual.clickgui.astolfo.AstolfoClickGUI; import works.alya.module.impl.visual.clickgui.dropdown.DropDownClickGUI; import net.minecraft.client.MinecraftClient; import org.lwjgl.glfw.GLFW; +@SuppressWarnings("FieldCanBeLocal") public class ClickGUIModule extends Module { + private final ModeSetting guiMode = new ModeSetting("GUI Mode", "GUI Mode", "Dropdown", "Dropdown", "Astolfo"); private final BooleanSetting showTooltips = new BooleanSetting("ShowTooltips", "Show tooltips when hovering over modules and settings", true); public ClickGUIModule() { @@ -35,12 +39,24 @@ public ClickGUIModule() { KeybindManager.getInstance().bind(this, GLFW.GLFW_KEY_RIGHT_SHIFT); AlyaClient.getEventBus().subscribe(this); + addSetting(guiMode); addSetting(showTooltips); } @Override protected void onEnable() { - MinecraftClient.getInstance().setScreen(new DropDownClickGUI(showTooltips.getValue())); + String mode = ((ModeSetting) getSetting("GUI Mode")).getValue(); + + switch(mode) { + case "Dropdown": + MinecraftClient.getInstance().setScreen(new DropDownClickGUI(showTooltips.getValue())); + break; + case "Astolfo": + MinecraftClient.getInstance().setScreen(new AstolfoClickGUI()); + break; + } + + super.onEnable(); super.setEnabled(false); } } \ No newline at end of file diff --git a/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java b/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java new file mode 100644 index 0000000..c3eb2be --- /dev/null +++ b/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java @@ -0,0 +1,396 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya 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 works.alya.module.impl.visual.clickgui.astolfo; + +import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.ModeSetting; +import works.alya.config.setting.impl.NumberSetting; +import works.alya.config.setting.Setting; +import works.alya.module.Module; +import works.alya.module.ModuleCategory; +import works.alya.module.ModuleRepository; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +import works.alya.utilities.render.*; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This ClickGUI was inspired by Astolfo Clients ClickGUI. + * The file is based on/adapted from + * Astolfo-Like-ClickGUI + * and modified to work inside FabricMC + */ +@SuppressWarnings({"rawtypes", "MismatchedQueryAndUpdateOfCollection"}) +public class AstolfoClickGUI extends Screen { + private final Map> categorizedModules = new EnumMap<>(ModuleCategory.class); + private final Map expandedCategories = new EnumMap<>(ModuleCategory.class); + private final Map expandedModules = new HashMap<>(); + private final Map categoryDragUtils = new EnumMap<>(ModuleCategory.class); + private final Map, Integer> numberSettingPositions = new HashMap<>(); + + private static final int PANEL_WIDTH = 100; + private static final int PANEL_HEIGHT = 18; + private static final int MODULE_HEIGHT = 18; + private static final int SETTING_HEIGHT = 9; + private static final int PANEL_SPACING = 120; + private static final int BACKGROUND_COLOR = 0xFF181A17; + private static final int MODULE_BACKGROUND_COLOR = 0xFF232623; + private static final int TEXT_COLOR = 0xFFFFFFFF; + private static final int BORDER_WIDTH = 2; + private static final int DEFAULT_CATEGORY_COLOR = 0xFF666666; + + private static final Map CATEGORY_COLORS = new EnumMap<>(ModuleCategory.class); + + static { + CATEGORY_COLORS.put(ModuleCategory.COMBAT, 0xFFE64D3A); + CATEGORY_COLORS.put(ModuleCategory.MOVEMENT, 0xFF2ECD6F); + CATEGORY_COLORS.put(ModuleCategory.WORLD, 0xFFE65F00); + CATEGORY_COLORS.put(ModuleCategory.VISUAL, 0xFF3A9DE6); + CATEGORY_COLORS.put(ModuleCategory.UTILITY, 0xffF29D11); + CATEGORY_COLORS.put(ModuleCategory.SCRIPTS, 0xFFE67300); + } + + private boolean dragging = false; + private int dragOffsetX = 0; + private int dragOffsetY = 0; + private ModuleCategory draggingCategory = null; + private NumberSetting currentDraggedNumberSetting = null; + private int currentDraggedSettingX = 0; + + public AstolfoClickGUI() { + super(Text.literal("Astolfo Click GUI")); + initializeModules(); + + int x = 4; + for(ModuleCategory category : ModuleCategory.values()) { + int finalX = x; + categoryDragUtils.computeIfAbsent(category, k -> new DragUtility(finalX, 4)); + x += PANEL_SPACING; + } + } + + private void initializeModules() { + categorizedModules.clear(); + expandedCategories.clear(); + + for(ModuleCategory category : ModuleCategory.values()) { + categorizedModules.put(category, new ArrayList<>()); + expandedCategories.put(category, false); + } + + ModuleRepository repository = works.alya.AlyaClient.INSTANCE.getModuleRepository(); + for(Module module : repository.getModules()) { + List categoryModules = categorizedModules.get(module.getCategory()); + if(categoryModules != null) { + categoryModules.add(module); + } + } + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + context.fill(0, 0, width, height, 0x80000000); + + for(ModuleCategory category : ModuleCategory.values()) { + renderCategoryPanel(context, category, mouseX, mouseY); + } + + super.render(context, mouseX, mouseY, delta); + } + + private void renderCategoryPanel(DrawContext context, ModuleCategory category, int mouseX, int mouseY) { + DragUtility dragUtil = categoryDragUtils.get(category); + if(dragUtil == null) return; + + int panelX = dragUtil.getX(); + int panelY = dragUtil.getY(); + + if(dragging && draggingCategory == category) { + panelX = mouseX + dragOffsetX; + panelY = mouseY + dragOffsetY; + dragUtil.setX(panelX); + dragUtil.setY(panelY); + } + + List modules = categorizedModules.get(category); + if(modules == null) return; + + int totalHeight = PANEL_HEIGHT; + + if(expandedCategories.get(category)) { + for(Module module : modules) { + totalHeight += MODULE_HEIGHT; + if(expandedModules.getOrDefault(module, false)) { + totalHeight += module.getSettings().size() * SETTING_HEIGHT; + } + } + } + + RenderUtility.drawRect(context, panelX, panelY, PANEL_WIDTH, PANEL_HEIGHT, BACKGROUND_COLOR); + + String categoryName = category.name().toLowerCase(); + TextRendererUtility.renderText(context, categoryName, TEXT_COLOR, panelX + 4, panelY + 5, false); + + if(expandedCategories.get(category)) { + int currentY = panelY + PANEL_HEIGHT; + + for(Module module : modules) { + renderModuleButton(context, module, panelX, currentY, category); + currentY += MODULE_HEIGHT; + + if(expandedModules.getOrDefault(module, false)) { + for(Setting setting : module.getSettings()) { + renderSettingButton(context, setting, panelX, currentY, category); + currentY += SETTING_HEIGHT; + } + } + } + } + + int categoryColor = getCategoryColor(category); + RenderUtility.drawRoundedRectOutline(context, panelX, panelY, PANEL_WIDTH, totalHeight, 0, BORDER_WIDTH, categoryColor); + + RenderUtility.drawRect(context, panelX, panelY + totalHeight, PANEL_WIDTH, 2, BACKGROUND_COLOR); + } + + private void renderModuleButton(DrawContext context, Module module, int x, int y, ModuleCategory category) { + RenderUtility.drawRect(context, x, y, PANEL_WIDTH, MODULE_HEIGHT, BACKGROUND_COLOR); + + boolean extended = expandedModules.getOrDefault(module, false); + if(!extended) { + int bgColor = module.isEnabled() ? getCategoryColor(category) : MODULE_BACKGROUND_COLOR; + RenderUtility.drawRect(context, x + 2, y, PANEL_WIDTH - 4, MODULE_HEIGHT, bgColor); + } else { + RenderUtility.drawRect(context, x + 2, y, PANEL_WIDTH - 4, MODULE_HEIGHT, BACKGROUND_COLOR); + } + + String moduleName = module.getName().toLowerCase(); + int textColor = extended ? (module.isEnabled() ? getCategoryColor(category) : TEXT_COLOR) : TEXT_COLOR; + int textX = x + PANEL_WIDTH - TextRendererUtility.getTextWidth(moduleName) - 3; + TextRendererUtility.renderText(context, moduleName, textColor, textX, y + 5, false); + } + + private void renderSettingButton(DrawContext context, Setting setting, int x, int y, ModuleCategory category) { + RenderUtility.drawRect(context, x, y, PANEL_WIDTH, SETTING_HEIGHT, BACKGROUND_COLOR); + + if(setting instanceof BooleanSetting boolSetting) { + if(boolSetting.getValue()) { + RenderUtility.drawRect(context, x + 3, y, PANEL_WIDTH - 6, SETTING_HEIGHT, getCategoryColor(category)); + } + TextRendererUtility.renderDynamicText( + context, + setting.getName(), + TEXT_COLOR, + x + 4, + y, + false, + "sf_pro_rounded_regular", + 8 + ); + + } else if(setting instanceof ModeSetting modeSetting) { + String text = setting.getName() + " > " + modeSetting.getValue(); + TextRendererUtility.renderDynamicText( + context, + text, + TEXT_COLOR, + x + 4, + y + 1, + false, + "sf_pro_rounded_regular", + 8 + ); + + } else if(setting instanceof NumberSetting numberSetting) { + numberSettingPositions.put(numberSetting, x); + + RenderUtility.drawRect(context, x, y, PANEL_WIDTH, SETTING_HEIGHT, BACKGROUND_COLOR); + + double value = numberSetting.getValue().doubleValue(); + double min = numberSetting.getMinValue().doubleValue(); + double max = numberSetting.getMaxValue().doubleValue(); + double percentage = (value - min) / (max - min); + + int fillWidth = (int) (percentage * (PANEL_WIDTH - 6)); + RenderUtility.drawRect(context, x + 3, y, fillWidth, SETTING_HEIGHT, getCategoryColor(category)); + + String text = setting.getName() + ": " + Math.round(value * 100.0) / 100.0; + TextRendererUtility.renderDynamicText( + context, + text, + TEXT_COLOR, + x + 4, + y, + false, + "sf_pro_rounded_regular", + 8 + ); + } + } + + private int getCategoryColor(ModuleCategory category) { + return CATEGORY_COLORS.getOrDefault(category, DEFAULT_CATEGORY_COLOR); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + int intMouseX = (int) mouseX; + int intMouseY = (int) mouseY; + + for(ModuleCategory category : ModuleCategory.values()) { + DragUtility dragUtil = categoryDragUtils.get(category); + if(dragUtil == null) continue; + + int panelX = dragUtil.getX(); + int panelY = dragUtil.getY(); + + if(isMouseOver(intMouseX, intMouseY, panelX, panelY, PANEL_HEIGHT)) { + if(button == 0) { + dragging = true; + draggingCategory = category; + dragOffsetX = panelX - intMouseX; + dragOffsetY = panelY - intMouseY; + } else if(button == 1) { + expandedCategories.put(category, !expandedCategories.get(category)); + } + return true; + } + + if(expandedCategories.get(category)) { + List modules = categorizedModules.get(category); + if(modules != null) { + int currentY = panelY + PANEL_HEIGHT; + + for(Module module : modules) { + if(isMouseOver(intMouseX, intMouseY, panelX, currentY, MODULE_HEIGHT)) { + if(button == 0) { + module.toggle(); + } else if(button == 1 && !module.getSettings().isEmpty()) { + expandedModules.put(module, !expandedModules.getOrDefault(module, false)); + } + return true; + } + currentY += MODULE_HEIGHT; + + if(expandedModules.getOrDefault(module, false)) { + for(Setting setting : module.getSettings()) { + if(isMouseOver(intMouseX, intMouseY, panelX, currentY, SETTING_HEIGHT)) { + if(setting instanceof NumberSetting numberSetting && button == 0) { + currentDraggedNumberSetting = numberSetting; + currentDraggedSettingX = panelX; + updateNumberSettingFromMouse(intMouseX); + } else { + handleSettingClick(setting, button); + } + return true; + } + currentY += SETTING_HEIGHT; + } + } + } + } + } + } + + return super.mouseClicked(mouseX, mouseY, button); + } + + private void handleSettingClick(Setting setting, int button) { + if(setting instanceof BooleanSetting boolSetting) { + boolSetting.setValue(!boolSetting.getValue()); + } else if(setting instanceof ModeSetting modeSetting) { + if(button == 0) { + modeSetting.cycle(); + } else if(button == 1) { + String currentValue = modeSetting.getValue(); + List modes = modeSetting.getModes(); + int currentIndex = modes.indexOf(currentValue); + int previousIndex = (currentIndex - 1 + modes.size()) % modes.size(); + modeSetting.setValue(modes.get(previousIndex)); + } + } + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if(dragging && draggingCategory != null) { + return true; + } + + if(currentDraggedNumberSetting != null) { + updateNumberSettingFromMouse((int) mouseX); + return true; + } + + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + dragging = false; + draggingCategory = null; + currentDraggedNumberSetting = null; + + return super.mouseReleased(mouseX, mouseY, button); + } + + @SuppressWarnings("unchecked") + private void updateNumberSettingFromMouse(int mouseX) { + if(currentDraggedNumberSetting == null) return; + + int settingX = currentDraggedSettingX; + int sliderStart = settingX + 3; + int sliderWidth = PANEL_WIDTH - 6; + + int relativeX = mouseX - sliderStart; + relativeX = Math.max(0, Math.min(relativeX, sliderWidth)); + + double percentage = (double) relativeX / sliderWidth; + + double min = currentDraggedNumberSetting.getMinValue().doubleValue(); + double max = currentDraggedNumberSetting.getMaxValue().doubleValue(); + double newValue = min + (percentage * (max - min)); + + Object currentValue = currentDraggedNumberSetting.getValue(); + var setting = (NumberSetting) currentDraggedNumberSetting; + if(currentValue instanceof Integer) { + setting.setValue((int) Math.round(newValue)); + } else if(currentValue instanceof Float) { + setting.setValue((float) newValue); + } else if(currentValue instanceof Double) { + setting.setValue(newValue); + } else if(currentValue instanceof Long) { + setting.setValue(Math.round(newValue)); + } + } + + private boolean isMouseOver(int mouseX, int mouseY, int x, int y, int height) { + return mouseX >= x && mouseX <= x + AstolfoClickGUI.PANEL_WIDTH && mouseY >= y && mouseY <= y + height; + } + + @Override + public boolean shouldPause() { + return false; + } + +} \ No newline at end of file diff --git a/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java b/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java index 806c2cf..338b58c 100644 --- a/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java +++ b/src/client/java/works/alya/module/impl/visual/clickgui/dropdown/DropDownClickGUI.java @@ -1,3 +1,4 @@ + /* * Copyright (c) Alya Client 2024-2025. * @@ -45,7 +46,6 @@ public class DropDownClickGUI extends Screen { private final Map categoryDragUtils = new EnumMap<>(ModuleCategory.class); private static final int SETTING_HEIGHT = 22; - private static final int SETTING_INDENT = 2; private static final int CATEGORY_HEIGHT = 18; private static final int MODULE_HEIGHT = 18; private static final int PANEL_WIDTH = 110; @@ -54,7 +54,7 @@ public class DropDownClickGUI extends Screen { private static final int PANEL_SPACING = 8; private static final int PADDING = 5; private static final int BACKGROUND_COLOR = 0xFF222222; - private static final int SETTING_BACKGROUND_COLOR = 0xFF121212;; + private static final int SETTING_BACKGROUND_COLOR = 0xFF121212; private static final int HOVER_COLOR = 0x30FFFFFF; private static final float CORNER_RADIUS = 6f; private static final int TOOLTIP_BACKGROUND = 0xFF000000; @@ -214,9 +214,9 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { RenderUtility.drawGradientRoundedRect( context, - categoryX, + categoryX + 1, y, - PANEL_WIDTH, + PANEL_WIDTH - 2, MODULE_HEIGHT, moduleRadius, primaryColor, @@ -229,7 +229,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { if(shouldRoundBottom) { hoverRadius = new Vector4f(0f, CORNER_RADIUS,0f , CORNER_RADIUS); } - RenderUtility.drawRoundedRect(context, categoryX, y, PANEL_WIDTH, MODULE_HEIGHT, hoverRadius, HOVER_COLOR); + RenderUtility.drawRoundedRect(context, categoryX + 1, y, PANEL_WIDTH - 2, MODULE_HEIGHT, hoverRadius, HOVER_COLOR); } int textColor = module.isEnabled() ? @@ -282,7 +282,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { RenderUtility.drawRoundedRect(context, categoryX + 1, y, PANEL_WIDTH - 2, SETTING_HEIGHT, hoverRadius, HOVER_COLOR); } - ColorUtility.Colors settingTextColor = ColorUtility.Colors.LIGHT_GRAY; + int settingTextColor = ColorUtility.getColor(ColorUtility.Colors.LIGHT_GRAY); TextRendererUtility.renderDynamicText( context, @@ -326,7 +326,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { TextRendererUtility.renderDynamicText( context, currentMode, - ColorUtility.Colors.LIGHT_GRAY, + ColorUtility.getColor(ColorUtility.Colors.LIGHT_GRAY), dropdownX + 2, dropdownY + 1, false, @@ -368,7 +368,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { TextRendererUtility.renderDynamicText( context, valueText, - ColorUtility.Colors.LIGHT_GRAY, + ColorUtility.getColor(ColorUtility.Colors.LIGHT_GRAY), sliderX + sliderWidth / 2 - TextRendererUtility.getTextWidth(valueText) / 2, y - 2, false, @@ -766,25 +766,12 @@ private void handleRightClick(int mouseX, int mouseY) { for(Setting setting : module.getSettings()) { if(!setting.isVisible()) continue; - int controlWidth = PANEL_WIDTH - TextRendererUtility.getTextWidth(setting.getName() + ": ") - PADDING * 6 - SETTING_INDENT; - int controlX = categoryX + PANEL_WIDTH - controlWidth - PADDING * 3; - int controlY = y + PADDING + 2; - int controlHeight = 14; - if(isMouseOver(mouseX, mouseY, categoryX, y, PANEL_WIDTH, SETTING_HEIGHT)) { switch(setting) { - case BooleanSetting booleanSetting -> { - booleanSetting.toggle(); - } - case ModeSetting modeSetting -> { - modeSetting.cycle(); - } - case NumberSetting numberSetting -> { - numberSetting.decrement(false); - } - case MultipleBooleanSetting multipleBooleanSetting -> { - multipleBooleanSetting.toggleExpanded(); - } + case BooleanSetting booleanSetting -> booleanSetting.toggle(); + case ModeSetting modeSetting -> modeSetting.cycle(); + case NumberSetting numberSetting -> numberSetting.decrement(false); + case MultipleBooleanSetting multipleBooleanSetting -> multipleBooleanSetting.toggleExpanded(); default -> { } } @@ -805,12 +792,8 @@ private boolean isMouseOver(int mouseX, int mouseY, int x, int y, int width, int mouseY >= y && mouseY <= y + height; } - private void renderGradientRoundedRect(DrawContext context, int x, int y, int width, int height, int color1, int color2, Vector4f radius) { - RenderUtility.drawGradientRoundedRect(context, x, y, width, height, radius, color1, color2); - } - @Override public boolean shouldPause() { return false; } -} \ No newline at end of file +} diff --git a/src/client/java/works/alya/utilities/render/TextRendererUtility.java b/src/client/java/works/alya/utilities/render/TextRendererUtility.java index 0cdcb42..bb2cf7d 100644 --- a/src/client/java/works/alya/utilities/render/TextRendererUtility.java +++ b/src/client/java/works/alya/utilities/render/TextRendererUtility.java @@ -123,7 +123,7 @@ public static void renderMdText( public static void renderDynamicText( DrawContext context, String text, - Colors color, + int color, int posX, int posY, boolean shadow, @@ -136,7 +136,7 @@ public static void renderDynamicText( text, posX, posY, - ColorUtility.getColor(color), + color, shadow ); } From 855059b30079807e223c338d0513121ab3b6aed2 Mon Sep 17 00:00:00 2001 From: Tristan Date: Tue, 8 Jul 2025 18:40:31 -0400 Subject: [PATCH 06/15] add scripting api: not complete, events not fully working update astolfo click gui --- build.gradle | 5 +- src/client/java/works/alya/AlyaClient.java | 3 + .../clickgui/astolfo/AstolfoClickGUI.java | 2 +- .../java/works/alya/script/ScriptManager.java | 0 .../java/works/alya/script/api/LuaAPI.java | 1175 +++++++++++++++++ .../java/works/alya/script/core/Script.java | 163 +++ .../works/alya/script/core/ScriptManager.java | 162 +++ .../alya/script/data/NumberSettingData.java | 23 + .../alya/script/data/RectRenderCommand.java | 32 + .../alya/script/data/TextRenderCommand.java | 32 + .../alya/script/integration/ScriptModule.java | 140 ++ .../script/integration/ScriptRenderQueue.java | 80 ++ .../script/interfaces/IRenderCommand.java | 26 + .../alya/utilities/misc/ChatUtility.java | 8 + 14 files changed, 1849 insertions(+), 2 deletions(-) delete mode 100644 src/client/java/works/alya/script/ScriptManager.java create mode 100644 src/client/java/works/alya/script/api/LuaAPI.java create mode 100644 src/client/java/works/alya/script/core/Script.java create mode 100644 src/client/java/works/alya/script/core/ScriptManager.java create mode 100644 src/client/java/works/alya/script/data/NumberSettingData.java create mode 100644 src/client/java/works/alya/script/data/RectRenderCommand.java create mode 100644 src/client/java/works/alya/script/data/TextRenderCommand.java create mode 100644 src/client/java/works/alya/script/integration/ScriptModule.java create mode 100644 src/client/java/works/alya/script/integration/ScriptRenderQueue.java create mode 100644 src/client/java/works/alya/script/interfaces/IRenderCommand.java diff --git a/build.gradle b/build.gradle index 602cfb0..cb6efba 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - // GraalVM JavaScript for scripting (replacement for Nashorn) + // GraalVM JavaScript for core (replacement for Nashorn) include(implementation('org.graalvm.js:js:22.3.1')) include(implementation('org.graalvm.js:js-scriptengine:22.3.1')) include(implementation('org.graalvm.regex:regex:22.3.1')) @@ -92,6 +92,9 @@ dependencies { // i do not want to make a renderer include(modImplementation("io.github.0x3c50.renderer:renderer-fabric:2.1.1")) + + // LuaJ for Lua core + include(implementation("org.luaj:luaj-jse:3.0.1")) } processResources { diff --git a/src/client/java/works/alya/AlyaClient.java b/src/client/java/works/alya/AlyaClient.java index bc47a7a..3451d3d 100644 --- a/src/client/java/works/alya/AlyaClient.java +++ b/src/client/java/works/alya/AlyaClient.java @@ -42,6 +42,7 @@ import works.alya.module.impl.world.TimerModule; import works.alya.module.impl.visual.clickgui.ClickGUIModule; import works.alya.module.impl.visual.esp.ESPModule; +import works.alya.script.core.ScriptManager; import works.alya.utilities.misc.IconLoader; import works.alya.utilities.misc.AlyaConstants; import net.fabricmc.api.ClientModInitializer; @@ -87,6 +88,8 @@ public void onInitializeClient() { KeybindManager.getInstance().initialize(); VisualManager.getInstance().initialize(); + ScriptManager.getInstance().init(); + CommandRegistrationCallback.EVENT.register(( dispatcher, registryAccess, diff --git a/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java b/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java index c3eb2be..06431f5 100644 --- a/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java +++ b/src/client/java/works/alya/module/impl/visual/clickgui/astolfo/AstolfoClickGUI.java @@ -95,7 +95,7 @@ private void initializeModules() { for(ModuleCategory category : ModuleCategory.values()) { categorizedModules.put(category, new ArrayList<>()); - expandedCategories.put(category, false); + expandedCategories.put(category, true); } ModuleRepository repository = works.alya.AlyaClient.INSTANCE.getModuleRepository(); diff --git a/src/client/java/works/alya/script/ScriptManager.java b/src/client/java/works/alya/script/ScriptManager.java deleted file mode 100644 index e69de29..0000000 diff --git a/src/client/java/works/alya/script/api/LuaAPI.java b/src/client/java/works/alya/script/api/LuaAPI.java new file mode 100644 index 0000000..02a7dee --- /dev/null +++ b/src/client/java/works/alya/script/api/LuaAPI.java @@ -0,0 +1,1175 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya 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 works.alya.script.api; + +import org.luaj.vm2.*; +import org.luaj.vm2.lib.TwoArgFunction; +import works.alya.AlyaClient; +import works.alya.event.IEventListener; +import works.alya.event.impl.MotionEvent; +import works.alya.module.Module; +import works.alya.module.ModuleRepository; +import works.alya.script.core.Script; +import works.alya.script.integration.ScriptModule; +import works.alya.script.integration.ScriptRenderQueue; +import works.alya.utilities.misc.ChatUtility; +import works.alya.utilities.player.MoveUtility; +import works.alya.utilities.render.ColorUtility; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Box; +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.Hand; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundCategory; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; +import org.luaj.vm2.lib.OneArgFunction; +import org.luaj.vm2.lib.VarArgFunction; +import org.luaj.vm2.lib.ZeroArgFunction; +import org.luaj.vm2.lib.jse.CoerceJavaToLua; +import org.luaj.vm2.lib.ThreeArgFunction; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.Collection; + +@SuppressWarnings("CallToPrintStackTrace") +public class LuaAPI { + private static final MinecraftClient mc = MinecraftClient.getInstance(); + private static LuaFunction motionEventCallback; + private static Script currentScript; + + public static void register(Globals globals, Script script) { + currentScript = script; + LuaTable alyaTable = new LuaTable(); + globals.set("alya", alyaTable); + + registerMinecraftAPI(alyaTable); + registerAlyaAPI(alyaTable); + registerRenderAPI(alyaTable); + registerUtilityAPI(alyaTable); + registerWorldAPI(alyaTable); + registerPlayerAPI(alyaTable); + registerInventoryAPI(alyaTable); + registerMathAPI(alyaTable); + registerNetworkAPI(alyaTable); + registerSoundAPI(alyaTable); + registerEntityAPI(alyaTable); + registerMotionEventAPI(alyaTable); + } + + public static void updateCurrentScript(Script script) { + currentScript = script; + } + + private static void registerMotionEventAPI(LuaTable alyaTable) { + LuaTable motionEventTable = new LuaTable(); + + IEventListener motionListener = event -> { + if(motionEventCallback != null && isScriptEnabled()) { + try { + motionEventCallback.call(CoerceJavaToLua.coerce(event)); + } catch(Exception ex) { + ChatUtility.sendError("Error in motion event callback"); + ChatUtility.sendScriptError(ex); + ex.printStackTrace(); + } + } + }; + + AlyaClient.getEventBus().register(motionListener); + + motionEventTable.set("setCallback", new TwoArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2) { + if(arg2.isfunction()) { + motionEventCallback = arg2.checkfunction(); + } + return NIL; + } + }); + + alyaTable.set("motionEvent", motionEventTable); + } + + private static boolean isScriptEnabled() { + if(currentScript == null) return false; + + for(Module module : AlyaClient.INSTANCE.getModuleRepository().getModules()) { + if(module instanceof ScriptModule scriptModule) { + if(scriptModule.getScript() == currentScript) { + return module.isEnabled(); + } + } + } + + return false; + } + + private static void registerMinecraftAPI(LuaTable alyaTable) { + LuaTable mcTable = new LuaTable(); + alyaTable.set("mc", mcTable); + + mcTable.set("getPlayer", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? CoerceJavaToLua.coerce(mc.player) : LuaValue.NIL; + } + }); + + mcTable.set("getPlayerPosition", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null) return LuaValue.NIL; + Vec3d pos = mc.player.getPos(); + LuaTable posTable = new LuaTable(); + posTable.set("x", pos.x); + posTable.set("y", pos.y); + posTable.set("z", pos.z); + return posTable; + } + }); + + mcTable.set("getPlayerSpeed", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(Double.parseDouble(AlyaClient.getBps())); + } + }); + + mcTable.set("getWorld", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.world != null ? CoerceJavaToLua.coerce(mc.world) : LuaValue.NIL; + } + }); + + mcTable.set("getEntities", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.world == null) return LuaValue.NIL; + List entities = new ArrayList<>(); + for(Entity entity : mc.world.getEntities()) { + entities.add(entity); + } + return CoerceJavaToLua.coerce(entities); + } + }); + + mcTable.set("getPlayers", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.world == null) return LuaValue.NIL; + List players = new ArrayList<>(); + for(Entity entity : mc.world.getEntities()) { + if(entity instanceof PlayerEntity) { + players.add((PlayerEntity) entity); + } + } + return CoerceJavaToLua.coerce(players); + } + }); + + mcTable.set("getFPS", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.getCurrentFps()); + } + }); + + mcTable.set("getGameTime", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.world != null ? LuaValue.valueOf(mc.world.getTime()) : LuaValue.valueOf(0); + } + }); + + mcTable.set("getDayTime", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.world != null ? LuaValue.valueOf(mc.world.getTimeOfDay()) : LuaValue.valueOf(0); + } + }); + + mcTable.set("isInGame", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.player != null && mc.world != null); + } + }); + + mcTable.set("getMouseX", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.mouse.getX()); + } + }); + + mcTable.set("getMouseY", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.mouse.getY()); + } + }); + + mcTable.set("getScreenWidth", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.getWindow().getScaledWidth()); + } + }); + + mcTable.set("getScreenHeight", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.getWindow().getScaledHeight()); + } + }); + } + + private static void registerAlyaAPI(LuaTable alyaTable) { + alyaTable.set("getModule", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String moduleName = arg.checkjstring(); + Module module = ModuleRepository.getInstance().getModuleByName(moduleName); + return module != null ? CoerceJavaToLua.coerce(module) : LuaValue.NIL; + } + }); + + alyaTable.set("isModuleEnabled", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String moduleName = arg.checkjstring(); + Module module = ModuleRepository.getInstance().getModuleByName(moduleName); + return LuaValue.valueOf(module != null && module.isEnabled()); + } + }); + + alyaTable.set("enableModule", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String moduleName = arg.checkjstring(); + Module module = ModuleRepository.getInstance().getModuleByName(moduleName); + if(module != null && !module.isEnabled()) { + module.setEnabled(true); + return LuaValue.TRUE; + } + return LuaValue.FALSE; + } + }); + + alyaTable.set("disableModule", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String moduleName = arg.checkjstring(); + Module module = ModuleRepository.getInstance().getModuleByName(moduleName); + if(module != null && module.isEnabled()) { + module.setEnabled(false); + return LuaValue.TRUE; + } + return LuaValue.FALSE; + } + }); + + alyaTable.set("toggleModule", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String moduleName = arg.checkjstring(); + Module module = ModuleRepository.getInstance().getModuleByName(moduleName); + if(module != null) { + module.toggle(); + return LuaValue.valueOf(module.isEnabled()); + } + return LuaValue.FALSE; + } + }); + + alyaTable.set("getModules", new ZeroArgFunction() { + @Override + public LuaValue call() { + Collection modules = ModuleRepository.getInstance().getModules(); + List moduleList = new ArrayList<>(modules); + return CoerceJavaToLua.coerce(moduleList); + } + }); + + alyaTable.set("getEnabledModules", new ZeroArgFunction() { + @Override + public LuaValue call() { + Collection modules = ModuleRepository.getInstance().getModules(); + List enabled = modules.stream() + .filter(Module::isEnabled) + .collect(Collectors.toList()); + return CoerceJavaToLua.coerce(enabled); + } + }); + } + + private static void registerRenderAPI(LuaTable alyaTable) { + LuaTable renderTable = new LuaTable(); + alyaTable.set("render", renderTable); + + renderTable.set("color", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(args.narg() == 1) { + String colorName = args.checkjstring(1); + try { + ColorUtility.Colors color = ColorUtility.Colors.valueOf(colorName.toUpperCase()); + return LuaValue.valueOf(ColorUtility.getColor(color)); + } catch(IllegalArgumentException e) { + ChatUtility.sendError("Invalid color name: " + colorName); + ChatUtility.sendScriptError(e); + return LuaValue.valueOf(0xFFFFFFFF); + } + } else if(args.narg() >= 3) { + int r = args.checkint(1); + int g = args.checkint(2); + int b = args.checkint(3); + int a = args.optint(4, 255); + Color color = new Color(r, g, b, a); + return LuaValue.valueOf(ColorUtility.getIntFromColor(color)); + } + return LuaValue.valueOf(0xFFFFFFFF); + } + }); + + renderTable.set("drawText", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + String text = args.checkjstring(1); + int x = args.checkint(2); + int y = args.checkint(3); + int color = args.optint(4, 0xFFFFFFFF); + boolean shadow = args.optboolean(5, false); + ScriptRenderQueue.addTextRenderCommand(text, x, y, color, shadow); + return LuaValue.NIL; + } + }); + + renderTable.set("drawRect", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + float x = (float) args.checkdouble(1); + float y = (float) args.checkdouble(2); + float width = (float) args.checkdouble(3); + float height = (float) args.checkdouble(4); + int color = args.optint(5, 0xFFFFFFFF); + ScriptRenderQueue.addRectRenderCommand(x, y, width, height, color); + return LuaValue.NIL; + } + }); + + renderTable.set("getStringWidth", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String text = arg.checkjstring(); + return LuaValue.valueOf(mc.textRenderer.getWidth(text)); + } + }); + + renderTable.set("getStringHeight", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(mc.textRenderer.fontHeight); + } + }); + } + + private static void registerUtilityAPI(LuaTable alyaTable) { + LuaTable utilTable = new LuaTable(); + alyaTable.set("util", utilTable); + + utilTable.set("log", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String message = arg.checkjstring(); + System.out.println("[Script] " + message); + return LuaValue.NIL; + } + }); + + utilTable.set("chatInfo", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String message = arg.checkjstring(); + ChatUtility.sendInfo(message); + return LuaValue.NIL; + } + }); + + utilTable.set("chatError", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + String message = arg.checkjstring(); + ChatUtility.sendError(message); + return LuaValue.NIL; + } + }); + + utilTable.set("setSpeed", new TwoArgFunction() { + @Override + public LuaValue call(LuaValue arg$1, LuaValue arg$2) { + double speed = arg$1.checkdouble(); + boolean strafe = arg$2.checkboolean(); + MoveUtility.setSpeed(speed, strafe); + return LuaValue.NIL; + } + }); + + utilTable.set("currentTimeMillis", new ZeroArgFunction() { + @Override + public LuaValue call() { + return LuaValue.valueOf(System.currentTimeMillis()); + } + }); + + utilTable.set("sleep", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + long ms = arg.checklong(); + try { + Thread.sleep(ms); + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + } + return LuaValue.NIL; + } + }); + + utilTable.set("randomInt", new TwoArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2) { + int min = arg1.checkint(); + int max = arg2.checkint(); + return LuaValue.valueOf(min + (int) (Math.random() * (max - min + 1))); + } + }); + + utilTable.set("randomDouble", new TwoArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2) { + double min = arg1.checkdouble(); + double max = arg2.checkdouble(); + return LuaValue.valueOf(min + Math.random() * (max - min)); + } + }); + } + + private static void registerWorldAPI(LuaTable alyaTable) { + LuaTable worldTable = new LuaTable(); + alyaTable.set("world", worldTable); + + worldTable.set("getBlock", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.NIL; + int x = args.checkint(1); + int y = args.checkint(2); + int z = args.checkint(3); + BlockPos pos = new BlockPos(x, y, z); + BlockState state = mc.world.getBlockState(pos); + return CoerceJavaToLua.coerce(state.getBlock()); + } + }); + + worldTable.set("getBlockState", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.NIL; + int x = args.checkint(1); + int y = args.checkint(2); + int z = args.checkint(3); + BlockPos pos = new BlockPos(x, y, z); + BlockState state = mc.world.getBlockState(pos); + return CoerceJavaToLua.coerce(state); + } + }); + + worldTable.set("isAir", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.FALSE; + int x = args.checkint(1); + int y = args.checkint(2); + int z = args.checkint(3); + BlockPos pos = new BlockPos(x, y, z); + return LuaValue.valueOf(mc.world.getBlockState(pos).isAir()); + } + }); + + worldTable.set("getLightLevel", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.valueOf(0); + int x = args.checkint(1); + int y = args.checkint(2); + int z = args.checkint(3); + BlockPos pos = new BlockPos(x, y, z); + return LuaValue.valueOf(mc.world.getLightLevel(pos)); + } + }); + + worldTable.set("getEntitiesInRange", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.NIL; + double x = args.checkdouble(1); + double y = args.checkdouble(2); + double z = args.checkdouble(3); + double range = args.checkdouble(4); + + Vec3d center = new Vec3d(x, y, z); + Box box = new Box(center.subtract(range, range, range), center.add(range, range, range)); + List entities = mc.world.getOtherEntities(null, box); + return CoerceJavaToLua.coerce(entities); + } + }); + + worldTable.set("raycast", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null || mc.player == null) return LuaValue.NIL; + double distance = args.optdouble(1, 4.5); + HitResult hit = mc.player.raycast(distance, 0, false); + return CoerceJavaToLua.coerce(hit); + } + }); + + worldTable.set("getDimension", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.world == null) return LuaValue.NIL; + return LuaValue.valueOf(mc.world.getRegistryKey().getValue().toString()); + } + }); + + worldTable.set("getWeather", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.world == null) return LuaValue.NIL; + LuaTable weather = new LuaTable(); + weather.set("raining", LuaValue.valueOf(mc.world.isRaining())); + weather.set("thundering", LuaValue.valueOf(mc.world.isThundering())); + weather.set("rainGradient", LuaValue.valueOf(mc.world.getRainGradient(0))); + weather.set("thunderGradient", LuaValue.valueOf(mc.world.getThunderGradient(0))); + return weather; + } + }); + } + + private static void registerPlayerAPI(LuaTable alyaTable) { + LuaTable playerTable = new LuaTable(); + alyaTable.set("player", playerTable); + + playerTable.set("getHealth", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getHealth()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getMaxHealth", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getMaxHealth()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getFoodLevel", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getHungerManager().getFoodLevel()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getSaturation", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getHungerManager().getSaturationLevel()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getExperience", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.experienceLevel) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getVelocity", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null) return LuaValue.NIL; + Vec3d vel = mc.player.getVelocity(); + LuaTable velTable = new LuaTable(); + velTable.set("x", vel.x); + velTable.set("y", vel.y); + velTable.set("z", vel.z); + return velTable; + } + }); + + playerTable.set("getYaw", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getYaw()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("getPitch", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getPitch()) : LuaValue.valueOf(0); + } + }); + + playerTable.set("isOnGround", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.isOnGround()) : LuaValue.FALSE; + } + }); + + playerTable.set("isTouchingWater", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.isTouchingWater()) : LuaValue.FALSE; + } + }); + + playerTable.set("isInLava", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.isInLava()) : LuaValue.FALSE; + } + }); + + playerTable.set("isCreative", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getAbilities().creativeMode) : LuaValue.FALSE; + } + }); + + playerTable.set("canFly", new ZeroArgFunction() { + @Override + public LuaValue call() { + return mc.player != null ? LuaValue.valueOf(mc.player.getAbilities().allowFlying) : LuaValue.FALSE; + } + }); + + playerTable.set("setPosition", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.player == null) return LuaValue.NIL; + double x = args.checkdouble(1); + double y = args.checkdouble(2); + double z = args.checkdouble(3); + mc.player.setPosition(x, y, z); + return LuaValue.NIL; + } + }); + + playerTable.set("setVelocity", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.player == null) return LuaValue.NIL; + double x = args.checkdouble(1); + double y = args.checkdouble(2); + double z = args.checkdouble(3); + mc.player.setVelocity(x, y, z); + return LuaValue.NIL; + } + }); + + playerTable.set("setYaw", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null) return LuaValue.NIL; + float yaw = (float) arg.checkdouble(); + mc.player.setYaw(yaw); + return LuaValue.NIL; + } + }); + + playerTable.set("setPitch", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null) return LuaValue.NIL; + float pitch = (float) arg.checkdouble(); + mc.player.setPitch(pitch); + return LuaValue.NIL; + } + }); + + playerTable.set("jump", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player != null) { + mc.player.jump(); + } + return LuaValue.NIL; + } + }); + + playerTable.set("swingHand", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player != null) { + mc.player.swingHand(Hand.MAIN_HAND); + } + return LuaValue.NIL; + } + }); + } + + private static void registerInventoryAPI(LuaTable alyaTable) { + LuaTable invTable = new LuaTable(); + alyaTable.set("inventory", invTable); + + invTable.set("getHeldItem", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null) return LuaValue.NIL; + ItemStack stack = mc.player.getMainHandStack(); + return CoerceJavaToLua.coerce(stack); + } + }); + + invTable.set("getOffHandItem", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null) return LuaValue.NIL; + ItemStack stack = mc.player.getOffHandStack(); + return CoerceJavaToLua.coerce(stack); + } + }); + + invTable.set("getSlot", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null) return LuaValue.NIL; + int slot = arg.checkint(); + if(slot < 0 || slot >= mc.player.getInventory().size()) return LuaValue.NIL; + ItemStack stack = mc.player.getInventory().getStack(slot); + return CoerceJavaToLua.coerce(stack); + } + }); + + invTable.set("getSelectedSlot", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null) return LuaValue.valueOf(0); + return LuaValue.valueOf(mc.player.getInventory().getSelectedSlot()); + } + }); + + invTable.set("setSelectedSlot", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null || mc.getNetworkHandler() == null) return LuaValue.NIL; + int slot = arg.checkint(); + if(slot >= 0 && slot < 9) { + mc.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(slot)); + } + return LuaValue.NIL; + } + }); + + invTable.set("findItem", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null) return LuaValue.valueOf(-1); + String itemName = arg.checkjstring(); + for(int i = 0; i < mc.player.getInventory().size(); i++) { + ItemStack stack = mc.player.getInventory().getStack(i); + if(!stack.isEmpty() && stack.getItem().toString().contains(itemName)) { + return LuaValue.valueOf(i); + } + } + return LuaValue.valueOf(-1); + } + }); + + invTable.set("getItemCount", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null) return LuaValue.valueOf(0); + String itemName = arg.checkjstring(); + int count = 0; + for(int i = 0; i < mc.player.getInventory().size(); i++) { + ItemStack stack = mc.player.getInventory().getStack(i); + if(!stack.isEmpty() && stack.getItem().toString().contains(itemName)) { + count += stack.getCount(); + } + } + return LuaValue.valueOf(count); + } + }); + } + + private static void registerMathAPI(LuaTable alyaTable) { + LuaTable mathTable = new LuaTable(); + alyaTable.set("math", mathTable); + + mathTable.set("distance", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + double x1 = args.checkdouble(1); + double y1 = args.checkdouble(2); + double z1 = args.checkdouble(3); + double x2 = args.checkdouble(4); + double y2 = args.checkdouble(5); + double z2 = args.checkdouble(6); + double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); + return LuaValue.valueOf(distance); + } + }); + + mathTable.set("distance2D", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + double x1 = args.checkdouble(1); + double z1 = args.checkdouble(2); + double x2 = args.checkdouble(3); + double z2 = args.checkdouble(4); + double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(z2 - z1, 2)); + return LuaValue.valueOf(distance); + } + }); + + mathTable.set("wrapAngle", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + float angle = (float) arg.checkdouble(); + return LuaValue.valueOf(MathHelper.wrapDegrees(angle)); + } + }); + + mathTable.set("angleTo", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.player == null) return LuaValue.NIL; + double x = args.checkdouble(1); + double y = args.checkdouble(2); + double z = args.checkdouble(3); + + Vec3d playerPos = mc.player.getPos(); + double deltaX = x - playerPos.x; + double deltaZ = z - playerPos.z; + double deltaY = y - (playerPos.y + mc.player.getEyeHeight(mc.player.getPose())); + + double yaw = Math.toDegrees(Math.atan2(deltaZ, deltaX)) - 90; + double pitch = -Math.toDegrees(Math.atan2(deltaY, Math.sqrt(deltaX * deltaX + deltaZ * deltaZ))); + + LuaTable angles = new LuaTable(); + angles.set("yaw", MathHelper.wrapDegrees((float) yaw)); + angles.set("pitch", MathHelper.wrapDegrees((float) pitch)); + return angles; + } + }); + + mathTable.set("lerp", new ThreeArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { + double start = arg1.checkdouble(); + double end = arg2.checkdouble(); + double factor = arg3.checkdouble(); + return LuaValue.valueOf(start + (end - start) * factor); + } + }); + + mathTable.set("clamp", new ThreeArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { + double value = arg1.checkdouble(); + double min = arg2.checkdouble(); + double max = arg3.checkdouble(); + return LuaValue.valueOf(Math.max(min, Math.min(max, value))); + } + }); + } + + private static void registerNetworkAPI(LuaTable alyaTable) { + LuaTable netTable = new LuaTable(); + alyaTable.set("network", netTable); + + netTable.set("sendPacket", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null || mc.getNetworkHandler() == null) return LuaValue.NIL; + Object packet = arg.checkuserdata(); + if(packet instanceof net.minecraft.network.packet.Packet) { + mc.getNetworkHandler().sendPacket((net.minecraft.network.packet.Packet) packet); + } + return LuaValue.NIL; + } + }); + + netTable.set("sendMovementPacket", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.player == null || mc.getNetworkHandler() == null) return LuaValue.NIL; + double x = args.checkdouble(1); + double y = args.checkdouble(2); + double z = args.checkdouble(3); + float yaw = (float) args.optdouble(4, mc.player.getYaw()); + float pitch = (float) args.optdouble(5, mc.player.getPitch()); + boolean onGround = args.optboolean(6, mc.player.isOnGround()); + boolean changePosition = args.optboolean(7, true); + + PlayerMoveC2SPacket packet = new PlayerMoveC2SPacket.Full(x, y, z, yaw, pitch, onGround, changePosition); + mc.getNetworkHandler().sendPacket(packet); + return LuaValue.NIL; + } + }); + + netTable.set("sendHandSwing", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null || mc.getNetworkHandler() == null) return LuaValue.NIL; + mc.getNetworkHandler().sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + return LuaValue.NIL; + } + }); + } + + private static void registerSoundAPI(LuaTable alyaTable) { + LuaTable soundTable = new LuaTable(); + alyaTable.set("sound", soundTable); + + soundTable.set("playSound", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.player == null || mc.world == null) return LuaValue.NIL; + String soundName = args.checkjstring(1); + float volume = (float) args.optdouble(2, 1.0); + float pitch = (float) args.optdouble(3, 1.0); + + try { + String[] parts = soundName.split(":"); + if(parts.length != 2) return LuaValue.NIL; + + Identifier soundId = Identifier.of(parts[0], parts[1]); + SoundEvent sound = Registries.SOUND_EVENT.get(soundId); + if(sound != null) { + mc.world.playSound(mc.player, mc.player.getBlockPos(), sound, SoundCategory.MASTER, volume, pitch); + } + } catch(Exception e) { + ChatUtility.sendError("Failed to play sound \"" + soundName + "\": " + e.getMessage()); + ChatUtility.sendScriptError(e); + } + return LuaValue.NIL; + } + }); + + soundTable.set("playSoundAt", new VarArgFunction() { + @Override + public Varargs invoke(Varargs args) { + if(mc.world == null) return LuaValue.NIL; + String soundName = args.checkjstring(1); + double x = args.checkdouble(2); + double y = args.checkdouble(3); + double z = args.checkdouble(4); + float volume = (float) args.optdouble(5, 1.0); + float pitch = (float) args.optdouble(6, 1.0); + + try { + String[] parts = soundName.split(":"); + if(parts.length != 2) return LuaValue.NIL; + + Identifier soundId = Identifier.of(parts[0], parts[1]); + SoundEvent sound = Registries.SOUND_EVENT.get(soundId); + if(sound != null) { + mc.world.playSound(null, new BlockPos((int) x, (int) y, (int) z), sound, SoundCategory.MASTER, volume, pitch); + } + } catch(Exception e) { + ChatUtility.sendError("Invalid sound name: " + soundName); + ChatUtility.sendScriptError(e); + } + return LuaValue.NIL; + } + }); + } + + private static void registerEntityAPI(LuaTable alyaTable) { + LuaTable entityTable = new LuaTable(); + alyaTable.set("entity", entityTable); + + entityTable.set("getClosestPlayer", new ZeroArgFunction() { + @Override + public LuaValue call() { + if(mc.player == null || mc.world == null) return LuaValue.NIL; + + PlayerEntity closest = null; + double closestDistance = Double.MAX_VALUE; + + for(Entity entity : mc.world.getEntities()) { + if(entity instanceof PlayerEntity player && entity != mc.player) { + double distance = mc.player.distanceTo(player); + if(distance < closestDistance) { + closestDistance = distance; + closest = player; + } + } + } + + return closest != null ? CoerceJavaToLua.coerce(closest) : LuaValue.NIL; + } + }); + + entityTable.set("getClosestEntity", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null || mc.world == null) return LuaValue.NIL; + + String entityType = arg.checkjstring(); + Entity closest = null; + double closestDistance = Double.MAX_VALUE; + + for(Entity entity : mc.world.getEntities()) { + if(entity != mc.player && entity.getType().toString().contains(entityType)) { + double distance = mc.player.distanceTo(entity); + if(distance < closestDistance) { + closestDistance = distance; + closest = entity; + } + } + } + + return closest != null ? CoerceJavaToLua.coerce(closest) : LuaValue.NIL; + } + }); + + entityTable.set("getEntityPosition", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + if(entity == null) return LuaValue.NIL; + + Vec3d pos = entity.getPos(); + LuaTable posTable = new LuaTable(); + posTable.set("x", pos.x); + posTable.set("y", pos.y); + posTable.set("z", pos.z); + return posTable; + } + }); + + entityTable.set("getEntityHealth", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + if(entity instanceof LivingEntity living) { + return LuaValue.valueOf(living.getHealth()); + } + return LuaValue.valueOf(0); + } + }); + + entityTable.set("getEntityMaxHealth", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + if(entity instanceof LivingEntity living) { + return LuaValue.valueOf(living.getMaxHealth()); + } + return LuaValue.valueOf(0); + } + }); + + entityTable.set("isEntityAlive", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + return LuaValue.valueOf(entity != null && entity.isAlive()); + } + }); + + entityTable.set("getEntityName", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + return entity != null ? LuaValue.valueOf(entity.getName().getString()) : LuaValue.NIL; + } + }); + + entityTable.set("getEntityType", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + Entity entity = (Entity) arg.checkuserdata(); + return entity != null ? LuaValue.valueOf(entity.getType().toString()) : LuaValue.NIL; + } + }); + + entityTable.set("getPlayersInRange", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg) { + if(mc.player == null || mc.world == null) return LuaValue.NIL; + + double range = arg.checkdouble(); + List players = new ArrayList<>(); + + for(Entity entity : mc.world.getEntities()) { + if(entity instanceof PlayerEntity player && entity != mc.player) { + if(mc.player.distanceTo(player) <= range) { + players.add(player); + } + } + } + + return CoerceJavaToLua.coerce(players); + } + }); + + entityTable.set("getEntitiesInRange", new TwoArgFunction() { + @Override + public LuaValue call(LuaValue arg1, LuaValue arg2) { + if(mc.player == null || mc.world == null) return LuaValue.NIL; + + double range = arg1.checkdouble(); + String entityType = arg2.checkjstring(); + List entities = new ArrayList<>(); + + for(Entity entity : mc.world.getEntities()) { + if(entity != mc.player && entity.getType().toString().contains(entityType)) { + if(mc.player.distanceTo(entity) <= range) { + entities.add(entity); + } + } + } + + return CoerceJavaToLua.coerce(entities); + } + }); + } +} diff --git a/src/client/java/works/alya/script/core/Script.java b/src/client/java/works/alya/script/core/Script.java new file mode 100644 index 0000000..e390b64 --- /dev/null +++ b/src/client/java/works/alya/script/core/Script.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya 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 works.alya.script.core; + +import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaValue; +import works.alya.script.data.NumberSettingData; +import works.alya.utilities.misc.ChatUtility; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a Lua script in the Alya Client. + * Contains script metadata and execution environment. + */ +@SuppressWarnings("CallToPrintStackTrace") +public class Script { + private final File file; + private final String name; + private final String description; + private final Globals globals; + private final Map settings = new HashMap<>(); + + /** + * Creates a new Script instance. + * + * @param file The Lua script file + * @param name The name of the script + * @param description The description of the script + * @param globals The Lua globals environment + */ + public Script(File file, String name, String description, Globals globals) { + this.file = file; + this.name = name; + this.description = description; + this.globals = globals; + + loadSettings(); + } + + /** + * Loads settings defined in the script. + */ + private void loadSettings() { + LuaValue settingsTable = globals.get("settings"); + if(!settingsTable.isnil() && settingsTable.istable()) { + LuaValue[] keys = settingsTable.checktable().keys(); + for(LuaValue key : keys) { + String settingName = key.tojstring(); + LuaValue settingValue = settingsTable.get(key); + + if(settingValue.isboolean()) { + settings.put(settingName, settingValue.toboolean()); + } else if(settingValue.istable()) { + LuaValue valueField = settingValue.get("value"); + LuaValue minField = settingValue.get("min"); + LuaValue maxField = settingValue.get("max"); + + if(!valueField.isnil()) { + if(valueField.isint()) { + int value = valueField.toint(); + int min = minField.isnil() ? Integer.MIN_VALUE : minField.toint(); + int max = maxField.isnil() ? Integer.MAX_VALUE : maxField.toint(); + settings.put(settingName, new NumberSettingData(value, min, max)); + } else if(valueField.isnumber()) { + double value = valueField.todouble(); + double min = minField.isnil() ? Double.MIN_VALUE : minField.todouble(); + double max = maxField.isnil() ? Double.MAX_VALUE : maxField.todouble(); + settings.put(settingName, new NumberSettingData(value, min, max)); + } else if(valueField.isstring()) { + settings.put(settingName, valueField.tojstring()); + } + } + } else if(settingValue.isint()) { + settings.put(settingName, new NumberSettingData(settingValue.toint(), 0, 100)); + } else if(settingValue.isnumber()) { + settings.put(settingName, new NumberSettingData(settingValue.todouble(), 0.0, 100.0)); + } else if(settingValue.isstring()) { + settings.put(settingName, settingValue.tojstring()); + } + } + } + } + + /** + * Calls a function in the script. + * + * @param functionName The name of the function to call + * @param args The arguments to pass to the function + */ + public void callFunction(String functionName, LuaValue... args) { + LuaValue function = globals.get(functionName); + if(function.isfunction()) { + try { + function.invoke(LuaValue.varargsOf(args)); + } catch(Exception ex) { + ChatUtility.sendError("Error calling function '" + functionName + "' in script '" + name + "'"); + ex.printStackTrace(); + } + } + } + + /** + * Gets the file for this script. + * + * @return The script file + */ + public File getFile() { + return file; + } + + /** + * Gets the name of this script. + * + * @return The script name + */ + public String getName() { + return name; + } + + /** + * Gets the description of this script. + * + * @return The script description + */ + public String getDescription() { + return description; + } + + /** + * Gets the Lua globals environment for this script. + * + * @return The Lua globals + */ + public Globals getGlobals() { + return globals; + } + + /** + * Gets the settings for this script. + * + * @return Map of setting name to value + */ + public Map getSettings() { + return settings; + } +} diff --git a/src/client/java/works/alya/script/core/ScriptManager.java b/src/client/java/works/alya/script/core/ScriptManager.java new file mode 100644 index 0000000..8b881bd --- /dev/null +++ b/src/client/java/works/alya/script/core/ScriptManager.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) Alya Client 2024-2025. + * + * This file belongs to Alya Client, + * an open-source Fabric injection client. + * Rye GitHub: https://github.com/AlyaClient/alya-beta.git + * + * THIS PROJECT DOES NOT HAVE A WARRANTY. + * + * Alya (and subsequently, its files) are all licensed under the MIT License. + * Alya 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 works.alya.script.core; + +import net.minecraft.client.MinecraftClient; +import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.lib.jse.JsePlatform; +import works.alya.AlyaClient; +import works.alya.script.api.LuaAPI; +import works.alya.script.integration.ScriptModule; +import works.alya.utilities.misc.ChatUtility; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Manages Lua scripts for the Alya Client. + * Handles loading, execution, and management of scripts. + */ +@SuppressWarnings({"CallToPrintStackTrace", "unused", "FieldCanBeLocal"}) +public class ScriptManager { + private static final ScriptManager INSTANCE = new ScriptManager(); + private final MinecraftClient mc = MinecraftClient.getInstance(); + private final List