diff --git a/src/main/java/meteordevelopment/meteorclient/commands/Commands.java b/src/main/java/meteordevelopment/meteorclient/commands/Commands.java index de498a625c..10f00eb57a 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/Commands.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/Commands.java @@ -7,65 +7,104 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import meteordevelopment.meteorclient.commands.commands.*; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.pathing.PathManagers; import meteordevelopment.meteorclient.utils.PostInit; import net.minecraft.command.CommandSource; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ConfigurationBuilder; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Collectors; import static meteordevelopment.meteorclient.MeteorClient.mc; public class Commands { public static final CommandDispatcher DISPATCHER = new CommandDispatcher<>(); public static final List COMMANDS = new ArrayList<>(); + private static final Set SCAN_PACKAGES = new HashSet<>(); + private static final Map> CONDITIONAL_COMMANDS = new HashMap<>(); + + static { + registerCommandPackage("meteordevelopment.meteorclient.commands.commands"); + } @PostInit(dependencies = PathManagers.class) public static void init() { - add(new VClipCommand()); - add(new HClipCommand()); - add(new DismountCommand()); - add(new DisconnectCommand()); - add(new DamageCommand()); - add(new DropCommand()); - add(new EnchantCommand()); - add(new FakePlayerCommand()); - add(new FriendsCommand()); - add(new CommandsCommand()); - add(new InventoryCommand()); - add(new NbtCommand()); - add(new NotebotCommand()); - add(new PeekCommand()); - add(new EnderChestCommand()); - add(new ProfilesCommand()); - add(new ReloadCommand()); - add(new ResetCommand()); - add(new SayCommand()); - add(new ServerCommand()); - add(new SwarmCommand()); - add(new ToggleCommand()); - add(new SettingCommand()); - add(new SpectateCommand()); - add(new GamemodeCommand()); - add(new SaveMapCommand()); - add(new MacroCommand()); - add(new ModulesCommand()); - add(new BindsCommand()); - add(new GiveCommand()); - add(new NameHistoryCommand()); - add(new BindCommand()); - add(new FovCommand()); - add(new RotationCommand()); - add(new WaypointCommand()); - add(new InputCommand()); - add(new WaspCommand()); - add(new LocateCommand()); - + loadCommands(); COMMANDS.sort(Comparator.comparing(Command::getName)); } + /** + * Registers a package to scan for commands. + * This should be called by addons during their initialization. + */ + public static void registerCommandPackage(String packageName) { + SCAN_PACKAGES.add(packageName); + } + + /** + * Registers a command to be loaded conditionally. + * + * @param commandClass The class of the command to register + * @param condition A supplier that returns true if the command should be loaded + */ + public static void registerConditionalCommand(Class commandClass, Supplier condition) { + CONDITIONAL_COMMANDS.put(commandClass.getName(), condition); + } + + public static void loadCommands() { + try { + int totalCount = 0; + int skippedCount = 0; + + ConfigurationBuilder config = new ConfigurationBuilder() + .forPackages(SCAN_PACKAGES.toArray(new String[0])) + .setScanners(Scanners.SubTypes) + .setParallel(true) + .setExpandSuperTypes(false); + + Reflections reflections = new Reflections(config); + Set> commandClasses = reflections.getSubTypesOf(Command.class); + + commandClasses = commandClasses.stream() + .filter(commandClass -> SCAN_PACKAGES.stream().anyMatch(pkg -> commandClass.getName().startsWith(pkg))) + .collect(Collectors.toSet()); + + for (Class commandClass : commandClasses) { + String className = commandClass.getName(); + if (CONDITIONAL_COMMANDS.containsKey(className) && !CONDITIONAL_COMMANDS.get(className).get()) { + MeteorClient.LOG.info("Skipping conditional command: {}", className); + skippedCount++; + continue; + } + + try { + if (Modifier.isAbstract(commandClass.getModifiers()) || commandClass.isInterface()) continue; + + Constructor constructor = commandClass.getDeclaredConstructor(); + constructor.setAccessible(true); + Command command = constructor.newInstance(); + add(command); + totalCount++; + } catch (NoSuchMethodException ignored) { + MeteorClient.LOG.error("Command {} does not have a no-args constructor", commandClass.getName()); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + MeteorClient.LOG.error("Failed to load command: {}", commandClass.getName(), e); + } + } + + MeteorClient.LOG.info("Loaded {} commands ({} skipped)", totalCount, skippedCount); + } catch (Exception e) { + MeteorClient.LOG.error("Failed to load commands", e); + } + } + public static void add(Command command) { COMMANDS.removeIf(existing -> existing.getName().equals(command.getName())); command.registerTo(DISPATCHER); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java index f9394db09b..6ca035d025 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java @@ -20,18 +20,8 @@ import meteordevelopment.meteorclient.systems.System; import meteordevelopment.meteorclient.systems.Systems; import meteordevelopment.meteorclient.systems.config.Config; -import meteordevelopment.meteorclient.systems.modules.combat.*; -import meteordevelopment.meteorclient.systems.modules.misc.*; -import meteordevelopment.meteorclient.systems.modules.misc.swarm.Swarm; -import meteordevelopment.meteorclient.systems.modules.movement.*; -import meteordevelopment.meteorclient.systems.modules.movement.elytrafly.ElytraFly; -import meteordevelopment.meteorclient.systems.modules.movement.speed.Speed; -import meteordevelopment.meteorclient.systems.modules.player.*; -import meteordevelopment.meteorclient.systems.modules.render.*; -import meteordevelopment.meteorclient.systems.modules.render.blockesp.BlockESP; -import meteordevelopment.meteorclient.systems.modules.render.marker.Marker; -import meteordevelopment.meteorclient.systems.modules.world.Timer; -import meteordevelopment.meteorclient.systems.modules.world.*; +import meteordevelopment.meteorclient.systems.modules.world.Excavator; +import meteordevelopment.meteorclient.systems.modules.world.InfinityMiner; import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.meteorclient.utils.misc.Keybind; import meteordevelopment.meteorclient.utils.misc.ValueComparableMap; @@ -43,17 +33,33 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import org.lwjgl.glfw.GLFW; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ConfigurationBuilder; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; +import java.util.stream.Collectors; import static meteordevelopment.meteorclient.MeteorClient.mc; public class Modules extends System { private static final List CATEGORIES = new ArrayList<>(); + private static final Set SCAN_PACKAGES = new HashSet<>(); + private static final Map> CONDITIONAL_MODULES = new HashMap<>(); + + static { + registerModulePackage("meteordevelopment.meteorclient.systems.modules"); + + registerConditionalModule(Excavator.class, () -> BaritoneUtils.IS_AVAILABLE); + registerConditionalModule(InfinityMiner.class, () -> BaritoneUtils.IS_AVAILABLE); + } - private final List modules = new ArrayList<>(); private final Map, Module> moduleInstances = new Reference2ReferenceOpenHashMap<>(); private final Map> groups = new Reference2ReferenceOpenHashMap<>(); @@ -71,12 +77,7 @@ public static Modules get() { @Override public void init() { - initCombat(); - initPlayer(); - initMovement(); - initRender(); - initWorld(); - initMisc(); + loadModules(); } @Override @@ -90,11 +91,74 @@ public void load(File folder) { super.load(folder); } + /** + * Registers a package to scan for modules. + * This should be called by addons during their initialization. + */ + public static void registerModulePackage(String packageName) { + SCAN_PACKAGES.add(packageName); + } + + /** + * Registers a module to be loaded conditionally. + * + * @param moduleClass The class of the module to register + * @param condition A supplier that returns true if the module should be loaded + */ + public static void registerConditionalModule(Class moduleClass, Supplier condition) { + CONDITIONAL_MODULES.put(moduleClass.getName(), condition); + } + + public void loadModules() { + try { + ConfigurationBuilder config = new ConfigurationBuilder() + .forPackages(SCAN_PACKAGES.toArray(new String[0])) + .setScanners(Scanners.SubTypes) + .setParallel(true) + .setExpandSuperTypes(false); + + Reflections reflections = new Reflections(config); + Set> moduleClasses = reflections.getSubTypesOf(Module.class); + + moduleClasses = moduleClasses.stream() + .filter(moduleClass -> SCAN_PACKAGES.stream().anyMatch(pkg -> moduleClass.getName().startsWith(pkg))) + .collect(Collectors.toSet()); + + int totalCount = 0; + int skippedCount = 0; + for (Class moduleClass : moduleClasses) { + String className = moduleClass.getName(); + if (CONDITIONAL_MODULES.containsKey(className) && !CONDITIONAL_MODULES.get(className).get()) { + MeteorClient.LOG.info("Skipping conditional module: {}", className); + skippedCount++; + continue; + } + + try { + if (Modifier.isAbstract(moduleClass.getModifiers()) || moduleClass.isInterface()) continue; + + Constructor constructor = moduleClass.getDeclaredConstructor(); + constructor.setAccessible(true); + Module module = constructor.newInstance(); + add(module); + totalCount++; + } catch (NoSuchMethodException ignored) { + MeteorClient.LOG.error("Module {} does not have a no-args constructor", moduleClass.getName()); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + MeteorClient.LOG.error("Failed to load module: {}", moduleClass.getName(), e); + } + } + + MeteorClient.LOG.info("Loaded {} modules ({} skipped)", totalCount, skippedCount); + } catch (Exception e) { + MeteorClient.LOG.error("Failed to load modules", e); + } + } + public void sortModules() { for (List modules : groups.values()) { modules.sort(Comparator.comparing(o -> o.title)); } - modules.sort(Comparator.comparing(o -> o.title)); } public static void registerCategory(Category category) { @@ -133,14 +197,6 @@ public Collection getAll() { return moduleInstances.values(); } - /** - * @deprecated Use {@link Modules#getAll()} instead. - */ - @Deprecated(forRemoval = true) - public List getList() { - return modules; - } - public int getCount() { return moduleInstances.size(); } @@ -243,12 +299,10 @@ private boolean onBinding(boolean isKey, int value, int modifiers) { if (moduleToBind.keybind.canBindTo(isKey, value, modifiers)) { moduleToBind.keybind.set(isKey, value, modifiers); moduleToBind.info("Bound to (highlight)%s(default).", moduleToBind.keybind); - } - else if (value == GLFW.GLFW_KEY_ESCAPE) { + } else if (value == GLFW.GLFW_KEY_ESCAPE) { moduleToBind.keybind.set(Keybind.none()); moduleToBind.info("Removed bind."); - } - else return false; + } else return false; MeteorClient.EVENT_BUS.post(ModuleBindChangedEvent.get(moduleToBind)); moduleToBind = null; @@ -378,201 +432,9 @@ public void add(Module module) { // Add the module moduleInstances.put(module.getClass(), module); - modules.add(module); getGroup(module.category).add(module); // Register color settings for the module module.settings.registerColorSettings(module); } - - private void initCombat() { - add(new AnchorAura()); - add(new AntiAnvil()); - add(new AntiBed()); - add(new ArrowDodge()); - add(new AutoAnvil()); - add(new AutoArmor()); - add(new AutoCity()); - add(new AutoEXP()); - add(new AutoTotem()); - add(new AutoTrap()); - add(new AutoWeapon()); - add(new AutoWeb()); - add(new BedAura()); - add(new BowAimbot()); - add(new BowSpam()); - add(new Burrow()); - add(new Criticals()); - add(new CrystalAura()); - add(new Hitboxes()); - add(new HoleFiller()); - add(new KillAura()); - add(new Offhand()); - add(new Quiver()); - add(new SelfAnvil()); - add(new SelfTrap()); - add(new SelfWeb()); - add(new Surround()); - } - - private void initPlayer() { - add(new AntiHunger()); - add(new AutoEat()); - add(new AutoClicker()); - add(new AutoFish()); - add(new AutoGap()); - add(new AutoMend()); - add(new AutoReplenish()); - add(new AutoTool()); - add(new BreakDelay()); - add(new ChestSwap()); - add(new EXPThrower()); - add(new FakePlayer()); - add(new FastUse()); - add(new GhostHand()); - add(new InstantRebreak()); - add(new LiquidInteract()); - add(new MiddleClickExtra()); - add(new Multitask()); - add(new NoInteract()); - add(new NoMiningTrace()); - add(new NoRotate()); - add(new NoStatusEffects()); - add(new OffhandCrash()); - add(new Portals()); - add(new PotionSaver()); - add(new Reach()); - add(new Rotation()); - add(new SpeedMine()); - } - - private void initMovement() { - add(new AirJump()); - add(new Anchor()); - add(new AntiAFK()); - add(new AntiVoid()); - add(new AutoJump()); - add(new AutoWalk()); - add(new AutoWasp()); - add(new Blink()); - add(new BoatFly()); - add(new ClickTP()); - add(new ElytraBoost()); - add(new ElytraFly()); - add(new EntityControl()); - add(new EntitySpeed()); - add(new FastClimb()); - add(new Flight()); - add(new GUIMove()); - add(new HighJump()); - add(new Jesus()); - add(new LongJump()); - add(new NoFall()); - add(new NoSlow()); - add(new Parkour()); - add(new ReverseStep()); - add(new SafeWalk()); - add(new Scaffold()); - add(new Slippy()); - add(new Sneak()); - add(new Speed()); - add(new Spider()); - add(new Sprint()); - add(new Step()); - add(new TridentBoost()); - add(new Velocity()); - } - - private void initRender() { - add(new BetterTab()); - add(new BetterTooltips()); - add(new BlockESP()); - add(new BlockSelection()); - add(new Blur()); - add(new BossStack()); - add(new Breadcrumbs()); - add(new BreakIndicators()); - add(new CameraTweaks()); - add(new Chams()); - add(new CityESP()); - add(new EntityOwner()); - add(new ESP()); - add(new Freecam()); - add(new FreeLook()); - add(new Fullbright()); - add(new HandView()); - add(new HoleESP()); - add(new ItemPhysics()); - add(new ItemHighlight()); - add(new LightOverlay()); - add(new LogoutSpots()); - add(new Marker()); - add(new Nametags()); - add(new NoRender()); - add(new PopChams()); - add(new StorageESP()); - add(new TimeChanger()); - add(new Tracers()); - add(new Trail()); - add(new Trajectories()); - add(new TunnelESP()); - add(new VoidESP()); - add(new WallHack()); - add(new WaypointsModule()); - add(new Xray()); - add(new Zoom()); - } - - private void initWorld() { - add(new AirPlace()); - add(new Ambience()); - add(new AutoBreed()); - add(new AutoBrewer()); - add(new AutoMount()); - add(new AutoNametag()); - add(new AutoShearer()); - add(new AutoSign()); - add(new AutoSmelter()); - add(new BuildHeight()); - add(new Collisions()); - add(new EChestFarmer()); - add(new EndermanLook()); - add(new Flamethrower()); - add(new HighwayBuilder()); - add(new LiquidFiller()); - add(new MountBypass()); - add(new NoGhostBlocks()); - add(new Nuker()); - add(new PacketMine()); - add(new StashFinder()); - add(new SpawnProofer()); - add(new Timer()); - add(new VeinMiner()); - - if (BaritoneUtils.IS_AVAILABLE) { - add(new Excavator()); - add(new InfinityMiner()); - } - } - - private void initMisc() { - add(new AntiPacketKick()); - add(new AutoLog()); - add(new AutoReconnect()); - add(new AutoRespawn()); - add(new BetterBeacons()); - add(new BetterChat()); - add(new BookBot()); - add(new DiscordPresence()); - add(new InventoryTweaks()); - add(new MessageAura()); - add(new NameProtect()); - add(new Notebot()); - add(new Notifier()); - add(new PacketCanceller()); - add(new ServerSpoof()); - add(new SoundBlocker()); - add(new Spam()); - add(new Swarm()); - } }