package com.arslaancodes.arslaansmagichax.modules; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.DrawContext; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import com.arslaancodes.arslaansmagichax.ArslaansMagicHax; import com.arslaancodes.arslaansmagichax.ArslaansMagicHaxClient; import com.arslaancodes.arslaansmagichax.modules.settings.Setting; import com.mojang.blaze3d.platform.InputConstants; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; public class ModuleManager { private boolean hudRegistered = false; private static final String CONFIG_FILE = "ArslaansMagicHax.properties"; private static Map previousKeyState = new HashMap<>(); public static void handleKeyPresses() { Minecraft client = Minecraft.getInstance(); if (client.player == null || client.screen != null) return; for (Module module : modules) { int key = module.getGlfwKeybinding(); if (key == -1) continue; boolean isPressed = InputConstants.isKeyDown(client.getWindow().getWindow(), key); boolean wasPressed = previousKeyState.getOrDefault(module, false); if (isPressed && !wasPressed) { boolean wasEnabled = module.isEnabled(); // use !wasEnabled in the chat message for edge cases e.g. modules that toggle themselves off on enable module.toggle(); if (!Objects.equals(module.getName(), "ClickGUI")) { client.player.displayClientMessage(Component.literal( "Toggled module " + module.getName() + " to " + (!wasEnabled ? "ON" : "OFF") ), false); } } previousKeyState.put(module, isPressed); } } private static List modules = new ArrayList<>(); public static ModuleManager INSTANCE = new ModuleManager(); public void register(Module module) { modules.add(module); } public static List getAllModules() { return modules; } public static List getEnabledModules() { return modules.stream().filter(Module::isEnabled).collect(Collectors.toList()); } public List getModulesWithCategory(Category category) { return modules.stream() .filter(module -> module.getCategory() == category) .collect(Collectors.toList()); } public static void tick() { for (Module module : modules) { module.tick(); } handleKeyPresses(); } public void registerHUD() { if (!hudRegistered) { HudRenderCallback.EVENT.register(this::onRenderHud); hudRegistered = true; } } private void onRenderHud(DrawContext drawContext, DeltaTracker renderTickCounter) { if (!ArslaansMagicHaxClient.hideModulesHUD.isEnabled()) { Font textRenderer = Minecraft.getInstance().font; float alpha = 1.0F; int i = Mth.ceil(alpha * 255.0F) << 24; // I don't know what this dark magic is but it works int x = 5; int y = 5; int titleColor = 16568909 | i; // weird magic drawContext.drawStringWithBackdrop(textRenderer, Component.literal("Arslaan's Magic Hax"), x, y, 50, titleColor); y += textRenderer.lineHeight + 4; for (Module module : ModuleManager.getEnabledModules()) { int color = 16777215 | i; // more magic I don't understand drawContext.drawString(textRenderer, Component.literal(module.getName()), x, y, color); y += textRenderer.lineHeight + 2; } } } public void close() { // save then disable all saveModuleStates(); for (Module module : modules) { module.setEnabled(false); } } public void loadModuleStates() { File file = new File(CONFIG_FILE); if (!file.exists()) return; try (FileInputStream fis = new FileInputStream(file)) { Properties properties = new Properties(); properties.load(fis); for (Module module : modules) { String enabled = properties.getProperty(module.getName() + ".enabled"); if (Objects.equals(enabled, "true")) { module.setEnabled(true); } else { module.setEnabled(false); } String keyStr = properties.getProperty(module.getName() + ".key"); if (keyStr != null) { try { module.setGlfwKeybinding(Integer.parseInt(keyStr)); } catch (NumberFormatException ignored) {} } for (Setting setting : module.getSettings()) { String value = properties.getProperty(module.getName() + "." + setting.getName()); if (value != null) { setting.setValueFromString(value); } } } } catch (IOException e) { ArslaansMagicHax.LOGGER.info("Failed to load module states and settings", e); } } public void saveModuleStates() { Properties properties = new Properties(); for (Module module : modules) { properties.setProperty(module.getName() + ".enabled", String.valueOf(module.isEnabled())); properties.setProperty(module.getName() + ".key", String.valueOf(module.getGlfwKeybinding())); for (Setting setting : module.getSettings()) { properties.setProperty(module.getName() + "." + setting.getName(), setting.getValueAsString()); } } try (FileOutputStream fos = new FileOutputStream(CONFIG_FILE)) { properties.store(fos, "Arslaan's Magic Hax - Module States & Settings"); } catch (IOException e) { ArslaansMagicHax.LOGGER.error("Failed to save module states and settings", e); } } }