diff --git a/src/client/java/works/alya/AlyaClient.java b/src/client/java/works/alya/AlyaClient.java index 3255155..477e428 100644 --- a/src/client/java/works/alya/AlyaClient.java +++ b/src/client/java/works/alya/AlyaClient.java @@ -16,6 +16,7 @@ package works.alya; +import works.alya.backend.BackendManager; import works.alya.command.CommandBuilder; import works.alya.command.CommandRepository; import works.alya.command.impl.*; @@ -27,8 +28,10 @@ import works.alya.module.impl.combat.AimAssistModule; import works.alya.module.impl.combat.AttackDelayModule; import works.alya.module.impl.combat.AutoClickerModule; +import works.alya.module.impl.combat.BacktrackModule; import works.alya.module.impl.combat.killaura.KillauraModule; import works.alya.module.impl.movement.*; +import works.alya.module.impl.movement.step.StepModule; import works.alya.module.impl.utility.antivoid.AntiVoidModule; import works.alya.module.impl.utility.disabler.DisablerModule; import works.alya.module.impl.visual.*; @@ -67,7 +70,7 @@ public class AlyaClient implements ClientModInitializer { public static final String MOD_ID = "alya"; public static final Logger LOGGER = LogManager.getLogger(MOD_ID); public static AlyaClient INSTANCE = new AlyaClient(); - private static String tenaState = "loading"; + private static String alyaState = "loading"; private final ModuleRepository moduleRepository = ModuleRepository.getInstance(); private static Vec3d lastPos = null; private static long lastMoveTime = 0; @@ -75,6 +78,7 @@ public class AlyaClient implements ClientModInitializer { private static final Set previouslyPressedKeys = new HashSet<>(); private static EventBus eventBus; private static boolean wasInGame = false; + public static BackendManager backendManager; @Override public void onInitializeClient() { @@ -124,16 +128,20 @@ public void onInitializeClient() { if(isInGame && !wasInGame) { VisualManager.getInstance().applyVisualData(); - LOGGER.info("Applied visual module data after joining world"); } if(!isInGame && wasInGame) { VisualManager.getInstance().saveVisualData(); - LOGGER.info("Saved visual module data after leaving world"); } wasInGame = isInGame; }); + + String userName = System.getProperty("user.name"); + String userIdHashed = String.valueOf(userName.hashCode()); + backendManager = new BackendManager(userIdHashed); + + backendManager.goOnline(); } private static void initializeModules() { @@ -174,7 +182,9 @@ private static void initializeModules() { new TargetStrafeModule(), new SpeedMonitorModule(), new AutoClickerModule(), - new AimAssistModule() + new AimAssistModule(), + new BacktrackModule(), + new StepModule() ); } @@ -200,11 +210,11 @@ public ModuleRepository getModuleRepository() { } public static String getState() { - return tenaState; + return alyaState; } public static void setState(String state) { - tenaState = state; + alyaState = state; } public static String getName() { @@ -265,4 +275,8 @@ public static String getBps() { public static String getTime() { return new java.text.SimpleDateFormat("hh:mm a").format(new Date()); } + + public static int getUsersOnline() { + return backendManager.getCurrentOnlineCount(); + } } diff --git a/src/client/java/works/alya/backend/BackendAPI.java b/src/client/java/works/alya/backend/BackendAPI.java new file mode 100644 index 0000000..09426f1 --- /dev/null +++ b/src/client/java/works/alya/backend/BackendAPI.java @@ -0,0 +1,120 @@ +/* + * 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.backend; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JsonNode; +import works.alya.AlyaClient; + +public class BackendAPI { + private static final String BASE_URL = "https://rye.thoq.dev/api/v1/users"; + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + + public BackendAPI() { + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + this.objectMapper = new ObjectMapper(); + } + + public void joinOnline(String userId, String sessionId) throws Exception { + String requestBody = """ + { + "userId": "%s", + "sessionId": "%s", + "action": "join" + } + """.formatted(userId, sessionId); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(BASE_URL)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .timeout(Duration.ofSeconds(30)) + .build(); + + HttpResponse response = httpClient.send(request, + HttpResponse.BodyHandlers.ofString()); + + if(response.statusCode() != 200) { + AlyaClient.LOGGER.error("Error: {} - {}", response.statusCode(), response.body()); + } + } + + public void sendHeartbeat(String userId, String sessionId) throws Exception { + String requestBody = """ + { + "userId": "%s", + "sessionId": "%s", + "action": "heartbeat" + } + """.formatted(userId, sessionId); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(BASE_URL)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .timeout(Duration.ofSeconds(30)) + .build(); + + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public void leaveOnline(String userId, String sessionId) throws Exception { + String requestBody = """ + { + "userId": "%s", + "sessionId": "%s", + "action": "leave" + } + """.formatted(userId, sessionId); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(BASE_URL)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .timeout(Duration.ofSeconds(30)) + .build(); + + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + public int getOnlineCount() throws Exception { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(BASE_URL)) + .header("Content-Type", "application/json") + .GET() + .timeout(Duration.ofSeconds(30)) + .build(); + + HttpResponse response = httpClient.send(request, + HttpResponse.BodyHandlers.ofString()); + + if(response.statusCode() == 200) { + JsonNode jsonResponse = objectMapper.readTree(response.body()); + return jsonResponse.get("onlineUsers").asInt(); + } + return -1; + } +} \ No newline at end of file diff --git a/src/client/java/works/alya/backend/BackendManager.java b/src/client/java/works/alya/backend/BackendManager.java new file mode 100644 index 0000000..5353ae4 --- /dev/null +++ b/src/client/java/works/alya/backend/BackendManager.java @@ -0,0 +1,77 @@ +/* + * 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.backend; + +import works.alya.AlyaClient; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.UUID; + +public class BackendManager { + private final BackendAPI client; + private final ScheduledExecutorService scheduler; + private final String userId; + private final String sessionId; + private volatile boolean isOnline = false; + + public BackendManager(String userId) { + this.client = new BackendAPI(); + this.scheduler = Executors.newScheduledThreadPool(1); + this.userId = userId; + this.sessionId = UUID.randomUUID().toString(); + } + + public void goOnline() { + try { + client.joinOnline(userId, sessionId); + isOnline = true; + + scheduler.scheduleAtFixedRate(() -> { + if (isOnline) { + try { + client.sendHeartbeat(userId, sessionId); + } catch (Exception e) { + AlyaClient.LOGGER.error("Heartbeat failed: {}", e.getMessage()); + } + } + }, 120, 120, TimeUnit.SECONDS); + } catch (Exception e) { + AlyaClient.LOGGER.error("Failed to go online: {}", e.getMessage()); + } + } + + public void goOffline() { + try { + isOnline = false; + client.leaveOnline(userId, sessionId); + scheduler.shutdown(); + } catch (Exception e) { + AlyaClient.LOGGER.error("Failed to go offline: {}", e.getMessage()); + } + } + + public int getCurrentOnlineCount() { + try { + return client.getOnlineCount(); + } catch (Exception e) { + AlyaClient.LOGGER.error("Failed to get online count: {}", e.getMessage()); + return -1; + } + } +} \ No newline at end of file diff --git a/src/client/java/works/alya/config/ConfigManager.java b/src/client/java/works/alya/config/ConfigManager.java index f7c2c73..cf40ac9 100644 --- a/src/client/java/works/alya/config/ConfigManager.java +++ b/src/client/java/works/alya/config/ConfigManager.java @@ -45,16 +45,16 @@ public class ConfigManager { if(!folder.exists()) { boolean result = folder.mkdirs(); if(!result) { - LOGGER.info("Bwoah! Failed to create config folder!"); + LOGGER.error("Bwoah! Failed to create config folder!"); } } } /** - * Saves the current configuration state of all modules, including their settings - * and keybinds, to a JSON file specified by the provided name. + * Saves the current configuration state of all modules, including their settings, + * to a JSON file specified by the provided name. * The configuration data includes whether the module is enabled, all associated - * module settings with their respective values and types, and any defined keybinds. + * module settings with their respective values and types. * If the file does not exist, it is created, and if it does exist, it is overwritten. * * @param name The name of the configuration file to save (excluding the file extension). @@ -62,10 +62,8 @@ public class ConfigManager { public static void saveConfig(String name) { Map config = new LinkedHashMap<>(); Map modulesConfig = new LinkedHashMap<>(); - Map keybinds = new LinkedHashMap<>(); for(Module module : AlyaClient.INSTANCE.getModuleRepository().getModules()) { - // Skip visual modules (except for enabled state) as they are handled by VisualManager if (module.getCategory() == ModuleCategory.VISUAL) { Map moduleConfig = new LinkedHashMap<>(); moduleConfig.put("enabled", module.isEnabled()); @@ -110,13 +108,9 @@ public static void saveConfig(String name) { modulesConfig.put(module.getName(), moduleConfig); Integer key = KeybindManager.getInstance().getKeyForModule(module); - if(key != null) { - keybinds.put(module.getName(), key); - } } config.put("modules", modulesConfig); - config.put("keybinds", keybinds); File configFile = new File(CONFIG_FOLDER + name + ".json"); try(Writer writer = new FileWriter(configFile)) { @@ -129,7 +123,7 @@ public static void saveConfig(String name) { /** * Loads a configuration file by its name, applies the settings to the respective - * modules and keybinds, and updates the client state. If the configuration file does + * modules, and updates the client state. If the configuration file does * not exist, an error message is displayed in chat. * * @param name The name of the configuration file to load, excluding the file extension. @@ -181,18 +175,6 @@ public static void loadConfig(String name) { } } } - - @SuppressWarnings("unchecked") - Map keybinds = (Map) config.get("keybinds"); - if(keybinds != null) { - KeybindManager keybindManager = KeybindManager.getInstance(); - for(Map.Entry entry : keybinds.entrySet()) { - Module module = AlyaClient.INSTANCE.getModuleRepository().getModuleByName(entry.getKey()); - if(module != null) { - keybindManager.bind(module, entry.getValue().intValue()); - } - } - } } } catch(IOException ex) { ex.printStackTrace(); diff --git a/src/client/java/works/alya/config/KeybindManager.java b/src/client/java/works/alya/config/KeybindManager.java index 7293bb5..7d79f95 100644 --- a/src/client/java/works/alya/config/KeybindManager.java +++ b/src/client/java/works/alya/config/KeybindManager.java @@ -64,7 +64,7 @@ private void ensureKeybindsFolder() { if(!folder.exists()) { boolean result = folder.mkdirs(); if(!result) { - LOGGER.info("Failed to create keybindings folder!"); + LOGGER.error("Failed to create keybindings folder!"); } } } diff --git a/src/client/java/works/alya/mixin/client/misc/MinecraftClientMixin.java b/src/client/java/works/alya/mixin/client/misc/MinecraftClientMixin.java index e5ef4db..4ebcc30 100644 --- a/src/client/java/works/alya/mixin/client/misc/MinecraftClientMixin.java +++ b/src/client/java/works/alya/mixin/client/misc/MinecraftClientMixin.java @@ -76,4 +76,9 @@ private void onPostTick(CallbackInfo ci) { AlyaClient.getEventBus().dispatch(event); } + + @Inject(method = "close", at = @At("HEAD")) + public void close(CallbackInfo ci) { + AlyaClient.backendManager.goOffline(); + } } 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 08b08cb..aa7968a 100644 --- a/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java +++ b/src/client/java/works/alya/mixin/client/ui/WatermarkTitleScreenMixin.java @@ -75,7 +75,9 @@ private void renderRyeLogo(LogoDrawer logoDrawer, DrawContext context, int width @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;III)V")) private void replaceVersionText(DrawContext context, net.minecraft.client.font.TextRenderer textRenderer, String text, int x, int y, int color) { - // we ignore demo, modded and version + String usersOnline = String.format("%s online", AlyaClient.getUsersOnline()); + + TextRendererUtility.renderText(context, usersOnline, ColorUtility.Colors.WHITE, x, y, false); } @Inject(method = "init", at = @At("HEAD")) diff --git a/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java b/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java index 9b600ca..81203c7 100644 --- a/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java +++ b/src/client/java/works/alya/module/impl/combat/AutoClickerModule.java @@ -99,6 +99,9 @@ public AutoClickerModule() { updateMouseStates(); if(randomizeCps.getValue() && System.currentTimeMillis() - Math.max(lastLeftClick, lastRightClick) > 1000) { + if(minCps.getValue() > maxCps.getValue()) { + minCps.setValue(maxCps.getValue()); + } currentCps = random.nextInt(maxCps.getValue() - minCps.getValue() + 1) + minCps.getValue(); } else { currentCps = cps.getValue(); diff --git a/src/client/java/works/alya/module/impl/combat/BacktrackModule.java b/src/client/java/works/alya/module/impl/combat/BacktrackModule.java new file mode 100644 index 0000000..aee9fd2 --- /dev/null +++ b/src/client/java/works/alya/module/impl/combat/BacktrackModule.java @@ -0,0 +1,209 @@ +/* + * 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.combat; + +import works.alya.config.setting.impl.BooleanSetting; +import works.alya.config.setting.impl.NumberSetting; +import works.alya.event.IEventListener; +import works.alya.event.impl.TickEvent; +import works.alya.module.Module; +import works.alya.module.ModuleCategory; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.util.Hand; +import net.minecraft.util.math.Vec3d; + +import java.util.*; +import java.util.List; + +/** + * TODO: Make it better + */ +public class BacktrackModule extends Module { + + /** + * Settings for controlling backtrack behavior + */ + private static final NumberSetting backtrackTime = new NumberSetting<>("BacktrackTime", "Maximum time to backtrack in milliseconds", 200, 0, 1000); + private static final BooleanSetting playersOnly = new BooleanSetting("PlayersOnly", "Only track player entities", true); + private static final NumberSetting maxDistance = new NumberSetting<>("MaxDistance", "Maximum distance to track entities", 15.0, 5.0, 30.0); + private static final BooleanSetting attackAtBacktrack = new BooleanSetting("AttackAtBacktrack", "Attack entities at their backtracked positions", true); + private static final NumberSetting attackRange = new NumberSetting<>("AttackRange", "Maximum attack range for backtracked positions", 4.0, 3.0, 8.0); + private final Map> positionHistory = new HashMap<>(); + + public BacktrackModule() { + super("Backtrack", "Allows hitting players at their previous positions when they move out of range", ModuleCategory.COMBAT); + + addSetting(backtrackTime); + addSetting(playersOnly); + addSetting(maxDistance); + addSetting(attackAtBacktrack); + addSetting(attackRange); + } + + @Override + protected void onEnable() { + super.onEnable(); + positionHistory.clear(); + } + + @Override + protected void onDisable() { + super.onDisable(); + positionHistory.clear(); + } + + /** + * Tracks entity positions and handles backtracking + */ + @SuppressWarnings("unused") + private final IEventListener tickEvent = event -> { + if(!isEnabled() || mc.world == null || mc.player == null) return; + + if(event.isPre()) { + trackEntityPositions(); + cleanupOldPositions(); + + if(mc.options.attackKey.isPressed() && attackAtBacktrack.getValue()) { + Entity target = findBestBacktrackedTarget(); + if(target != null) { + attackEntity(target); + } + } + } + }; + + /** + * Tracks the positions of all relevant entities in the world + */ + private void trackEntityPositions() { + if(mc.world == null || mc.player == null) return; + + double trackDistance = maxDistance.getValue(); + + for(Entity entity : mc.world.getEntities()) { + if(!(entity instanceof LivingEntity) || entity == mc.player) continue; + if(playersOnly.getValue() && !(entity instanceof PlayerEntity)) continue; + if(entity.squaredDistanceTo(mc.player) > trackDistance * trackDistance) continue; + + addPositionToHistory(entity.getId(), entity.getPos()); + } + } + + /** + * Adds a position to the entity's position history + */ + private void addPositionToHistory(int entityId, Vec3d position) { + long currentTime = System.currentTimeMillis(); + + List positions = positionHistory.computeIfAbsent(entityId, k -> new ArrayList<>()); + + if(positions.isEmpty() || positions.getLast().position.squaredDistanceTo(position) > 0.0001) { + positions.add(new PositionData(position, currentTime)); + } + } + + /** + * Cleans up old position data that exceeds the backtrack time + */ + private void cleanupOldPositions() { + long currentTime = System.currentTimeMillis(); + long maxAge = backtrackTime.getValue(); + + positionHistory.forEach((entityId, positions) -> positions.removeIf(data -> currentTime - data.timestamp > maxAge)); + + positionHistory.entrySet().removeIf(entry -> entry.getValue().isEmpty()); + } + + /** + * Finds the best entity to attack based on backtracked positions + */ + private Entity findBestBacktrackedTarget() { + if(mc.player == null || mc.world == null) return null; + + Vec3d eyePos = mc.player.getEyePos(); + Vec3d lookVec = mc.player.getRotationVec(1.0f); + double maxAttackRange = attackRange.getValue(); + + Entity bestTarget = null; + double bestScore = Double.MAX_VALUE; + Vec3d bestPosition = null; + + for(Map.Entry> entry : positionHistory.entrySet()) { + int entityId = entry.getKey(); + List positions = entry.getValue(); + + Entity entity = mc.world.getEntityById(entityId); + if(!(entity instanceof LivingEntity) || entity == mc.player) continue; + + for(int i = positions.size() - 1; i >= 0; i--) { + PositionData posData = positions.get(i); + Vec3d historicalPos = posData.position; + + double historicalDistance = eyePos.distanceTo(historicalPos.add(0, entity.getHeight() / 2, 0)); + + if(historicalDistance <= maxAttackRange) { + Vec3d toEntity = historicalPos.add(0, entity.getHeight() / 2, 0).subtract(eyePos).normalize(); + double dot = lookVec.dotProduct(toEntity); + + if(dot > 0.5) { + long age = System.currentTimeMillis() - posData.timestamp; + double score = historicalDistance * (1.0 - dot) + (age / 1000.0); + + if(score < bestScore) { + bestScore = score; + bestTarget = entity; + bestPosition = historicalPos; + } + } + } + } + } + + if(bestTarget != null) { + double distance = eyePos.distanceTo(bestPosition); + setPrefix(String.format("%.1f", distance)); + } else { + setPrefix(""); + } + + return bestTarget; + } + + /** + * Attacks an entity by sending a packet directly to the server + */ + private void attackEntity(Entity entity) { + if(mc.player == null || mc.getNetworkHandler() == null) return; + + PlayerInteractEntityC2SPacket packet = PlayerInteractEntityC2SPacket.attack( + entity, + mc.player.isSneaking() + ); + + mc.getNetworkHandler().sendPacket(packet); + mc.player.swingHand(Hand.MAIN_HAND); + } + + /** + * Class to store position data with timestamp + */ + private record PositionData(Vec3d position, long timestamp) { + } +} \ No newline at end of file diff --git a/src/client/java/works/alya/module/impl/movement/SprintModule.java b/src/client/java/works/alya/module/impl/movement/SprintModule.java index f41cfa9..9e36580 100644 --- a/src/client/java/works/alya/module/impl/movement/SprintModule.java +++ b/src/client/java/works/alya/module/impl/movement/SprintModule.java @@ -38,14 +38,13 @@ public SprintModule() { if(mc.getNetworkHandler() == null || mc.player == null || mc.options == null || !event.isPre()) return; boolean omniSprintEnabled = ((BooleanSetting) getSetting("OmniSprint")).getValue(); - boolean movingForwards = mc.options.forwardKey.isPressed(); if(MoveUtility.isMoving()) { if(omniSprintEnabled) { mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_SPRINTING)); mc.player.setSprinting(true); - } else if(movingForwards) { - mc.player.setSprinting(true); + } else { + mc.options.sprintKey.setPressed(true); } } }; diff --git a/src/client/java/works/alya/module/impl/movement/flight/verus/VerusPacketFlight.java b/src/client/java/works/alya/module/impl/movement/flight/verus/VerusPacketFlight.java index 2d57802..eb24c68 100644 --- a/src/client/java/works/alya/module/impl/movement/flight/verus/VerusPacketFlight.java +++ b/src/client/java/works/alya/module/impl/movement/flight/verus/VerusPacketFlight.java @@ -35,21 +35,22 @@ public VerusPacketFlight(final Module parent) { super("VerusPacket", parent); } + @SuppressWarnings("unused") private final IEventListener onMotion = event -> { if(!event.isPre()) return; if(mc.player == null || mc.getNetworkHandler() == null) return; - ChatUtility.sendDebug("Sending funny packets..."); Vec3d playerPos = mc.player.getPos().add(0, -1, 0); BlockPos blockPos = new BlockPos((int) playerPos.x, (int) playerPos.y, (int) playerPos.z); - BlockHitResult hitResult = new BlockHitResult(playerPos, Direction.UP, blockPos, false); + BlockHitResult hitResult = new BlockHitResult(playerPos, Direction.DOWN, blockPos, false); - ChatUtility.sendDebug("RESULT: " + hitResult); + ChatUtility.sendDebug("BlockResult: " + hitResult); PlayerInteractBlockC2SPacket placePacket = new PlayerInteractBlockC2SPacket(Hand.MAIN_HAND, hitResult, 0); event.setPitch(90f); + ChatUtility.sendDebug("Sending funny packets..."); mc.getNetworkHandler().sendPacket(placePacket); MoveUtility.setMotionY(0); @@ -60,5 +61,4 @@ public VerusPacketFlight(final Module parent) { MoveUtility.setSpeed(0); } }; - } diff --git a/src/client/java/works/alya/module/impl/movement/step/StepModule.java b/src/client/java/works/alya/module/impl/movement/step/StepModule.java new file mode 100644 index 0000000..157783e --- /dev/null +++ b/src/client/java/works/alya/module/impl/movement/step/StepModule.java @@ -0,0 +1,60 @@ +package works.alya.module.impl.movement.step; + +import works.alya.config.setting.impl.NumberSetting; +import works.alya.event.IEventListener; +import works.alya.event.impl.MotionEvent; +import works.alya.module.Module; +import works.alya.module.ModuleCategory; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; + +public class StepModule extends Module { + + private static final NumberSetting stepHeight = new NumberSetting<>("Height", "Maximum step height", 2, 1, 10); + + public StepModule() { + super("Step", "Allows you to step up blocks higher than normal", ModuleCategory.MOVEMENT); + addSetting(stepHeight); + } + + @SuppressWarnings("unused") + private final IEventListener motionEvent = event -> { + if(mc.player == null || !event.isPre() || mc.world == null) return; + + if(mc.player.horizontalCollision && mc.player.isOnGround()) { + Vec3d playerPos = mc.player.getPos(); + Vec3d lookDirection = mc.player.getRotationVec(1.0f); + + BlockPos frontBlock = new BlockPos((int)(playerPos.x + lookDirection.x), (int)playerPos.y, (int)(playerPos.z + lookDirection.z)); + + if(!mc.world.getBlockState(frontBlock).isAir()) { + int targetHeight = findStepHeight(frontBlock); + + if(targetHeight > 0 && targetHeight <= stepHeight.getValue()) { + double newY = frontBlock.getY() + targetHeight; + if(newY - playerPos.y <= stepHeight.getValue()) { + mc.player.setPosition(playerPos.x, newY, playerPos.z); + } + } + } + } + }; + + private int findStepHeight(BlockPos startPos) { + if(mc.world == null || mc.player == null) return 0; + + for(int height = 1; height <= stepHeight.getValue(); height++) { + BlockPos checkPos = startPos.up(height); + BlockPos abovePos = checkPos.up(); + + if(mc.world.getBlockState(checkPos).isAir() && mc.world.getBlockState(abovePos).isAir()) { + Box playerBox = mc.player.getBoundingBox().offset(0, height, 0); + if(mc.world.isSpaceEmpty(mc.player, playerBox)) { + return height; + } + } + } + return 0; + } +} \ No newline at end of file diff --git a/src/client/java/works/alya/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java b/src/client/java/works/alya/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java index 20f1c61..473402f 100644 --- a/src/client/java/works/alya/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java +++ b/src/client/java/works/alya/module/impl/utility/disabler/cubecraft/CubecraftDisabler.java @@ -20,6 +20,7 @@ import works.alya.event.impl.MotionEvent; import works.alya.module.Module; import works.alya.module.SubModule; +import works.alya.utilities.misc.ChatUtility; public class CubecraftDisabler extends SubModule { public CubecraftDisabler(Module parent) { diff --git a/src/client/java/works/alya/script/api/LuaAPI.java b/src/client/java/works/alya/script/api/LuaAPI.java index bb620b0..c4dd480 100644 --- a/src/client/java/works/alya/script/api/LuaAPI.java +++ b/src/client/java/works/alya/script/api/LuaAPI.java @@ -22,7 +22,6 @@ 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; @@ -87,20 +86,6 @@ public void updateCurrentScript(Script script) { currentScript = script; } - private 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 void registerMinecraftAPI(Globals globals) { LuaTable mcTable = new LuaTable(); globals.set("mc", mcTable); @@ -312,10 +297,12 @@ public Varargs invoke(Varargs args) { 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) { @@ -326,6 +313,7 @@ public Varargs invoke(Varargs args) { Color color = new Color(r, g, b, a); return LuaValue.valueOf(ColorUtility.getIntFromColor(color)); } + return LuaValue.valueOf(0xFFFFFFFF); } }); @@ -341,6 +329,7 @@ public Varargs invoke(Varargs args) { ScriptRenderQueue.setCurrentScript(currentScript); ScriptRenderQueue.addTextRenderCommand(text, x, y, color, shadow); + return LuaValue.NIL; } }); @@ -356,6 +345,7 @@ public Varargs invoke(Varargs args) { ScriptRenderQueue.setCurrentScript(currentScript); ScriptRenderQueue.addRectRenderCommand(x, y, width, height, color); + return LuaValue.NIL; } }); @@ -384,7 +374,7 @@ private void registerUtilityAPI(Globals globals) { @Override public LuaValue call(LuaValue arg) { String message = arg.checkjstring(); - System.out.println("[Script] " + message); + AlyaClient.LOGGER.info(message); return LuaValue.NIL; } }); @@ -412,7 +402,9 @@ public LuaValue call(LuaValue arg) { 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; } }); @@ -433,6 +425,7 @@ public LuaValue call(LuaValue arg) { } catch(InterruptedException e) { Thread.currentThread().interrupt(); } + return LuaValue.NIL; } }); @@ -464,11 +457,14 @@ private void registerWorldAPI(Globals globals) { @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()); } }); @@ -477,11 +473,14 @@ public Varargs invoke(Varargs args) { @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); } }); @@ -490,10 +489,13 @@ public Varargs invoke(Varargs args) { @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()); } }); @@ -502,10 +504,13 @@ public Varargs invoke(Varargs args) { @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)); } }); @@ -514,6 +519,7 @@ public Varargs invoke(Varargs args) { @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); diff --git a/src/client/java/works/alya/script/core/ScriptManager.java b/src/client/java/works/alya/script/core/ScriptManager.java index 7037f74..a79803f 100644 --- a/src/client/java/works/alya/script/core/ScriptManager.java +++ b/src/client/java/works/alya/script/core/ScriptManager.java @@ -48,11 +48,10 @@ public class ScriptManager { private ScriptManager() { scriptsDir = new File(mc.runDirectory, "Alya/scripts"); - if(!scriptsDir.exists()) { - if(!scriptsDir.mkdirs()) { - System.err.println("Failed to create scripts directory: " + scriptsDir.getAbsolutePath()); - } - } + if(scriptsDir.exists()) return; + if(scriptsDir.mkdirs()) return; + + AlyaClient.LOGGER.error("Failed to create scripts directory: {}", scriptsDir.getAbsolutePath()); } public static ScriptManager getInstance() { diff --git a/src/client/java/works/alya/utilities/misc/IconLoader.java b/src/client/java/works/alya/utilities/misc/IconLoader.java index 6604248..bc65150 100644 --- a/src/client/java/works/alya/utilities/misc/IconLoader.java +++ b/src/client/java/works/alya/utilities/misc/IconLoader.java @@ -20,6 +20,7 @@ import net.fabricmc.api.Environment; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWImage; +import works.alya.AlyaClient; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; @@ -55,13 +56,10 @@ public static void setWindowIcon(long windowHandle) { GLFW.glfwSetWindowIcon(windowHandle, iconImages); iconImages.free(); - - System.out.println("Custom icons loaded successfully!"); - } catch(IOException e) { - System.err.println("Failed to load custom icon: " + e.getMessage()); + AlyaClient.LOGGER.error("Failed to load custom icon: {}", e.getMessage()); } catch(NullPointerException e) { - System.err.println("Icon not found or path incorrect: " + e.getMessage()); + AlyaClient.LOGGER.error("Icon not found or path incorrect: {}", e.getMessage()); } } diff --git a/src/main/resources/assets/alya/icon.png b/src/main/resources/assets/alya/icon.png index 0fbce46..ceb6005 100644 Binary files a/src/main/resources/assets/alya/icon.png and b/src/main/resources/assets/alya/icon.png differ diff --git a/src/main/resources/assets/alya/icons/icon.png b/src/main/resources/assets/alya/icons/icon.png index 0fbce46..ceb6005 100644 Binary files a/src/main/resources/assets/alya/icons/icon.png and b/src/main/resources/assets/alya/icons/icon.png differ diff --git a/src/main/resources/assets/alya/icons/icon16.png b/src/main/resources/assets/alya/icons/icon16.png index fe4691e..b940497 100644 Binary files a/src/main/resources/assets/alya/icons/icon16.png and b/src/main/resources/assets/alya/icons/icon16.png differ diff --git a/src/main/resources/assets/alya/icons/icon32.png b/src/main/resources/assets/alya/icons/icon32.png index bcf992f..0e362a8 100644 Binary files a/src/main/resources/assets/alya/icons/icon32.png and b/src/main/resources/assets/alya/icons/icon32.png differ diff --git a/src/main/resources/assets/alya/images/alya_logo.png b/src/main/resources/assets/alya/images/alya_logo.png index 018e9af..131e590 100644 Binary files a/src/main/resources/assets/alya/images/alya_logo.png and b/src/main/resources/assets/alya/images/alya_logo.png differ