diff --git a/.github/workflows/auto_build.yml b/.github/workflows/auto_build.yml new file mode 100644 index 0000000..bd58d94 --- /dev/null +++ b/.github/workflows/auto_build.yml @@ -0,0 +1,47 @@ +name: Auto Build on Push +on: + push: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', 'gradle/wrapper/**', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 21 + cache: 'gradle' + + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: Build with Gradle + run: ./gradlew build -Pcommit=${{ github.sha }} + env: + CI: true + + - name: Upload Build Archive + uses: actions/upload-artifact@v4 + with: + name: build-archive + path: build/libs/*.jar diff --git a/.github/workflows/dev_build.yml b/.github/workflows/dev_build.yml.disabled similarity index 100% rename from .github/workflows/dev_build.yml rename to .github/workflows/dev_build.yml.disabled diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml.disabled similarity index 100% rename from .github/workflows/pull_request.yml rename to .github/workflows/pull_request.yml.disabled diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72b3219..dc23a28 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,12 +29,12 @@ jobs: run: | mod_version=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2) echo "mod_version=$mod_version" >> $GITHUB_OUTPUT - echo "mc_version=1.21.4" >> $GITHUB_OUTPUT + echo "mc_version=1.21.5" >> $GITHUB_OUTPUT - name: Create GitHub Release Draft uses: softprops/action-gh-release@v2 with: - tag_name: v${{ steps.get_versions.outputs.mod_version }} + tag_name: v${{ steps.get_versions.outputs.mod_version }}-mc${{ steps.get_versions.outputs.mc_version }} name: Release v${{ steps.get_versions.outputs.mod_version }} (MC ${{ steps.get_versions.outputs.mc_version }}) body: | Release for mod version ${{ steps.get_versions.outputs.mod_version }} and Minecraft ${{ steps.get_versions.outputs.mc_version }}. diff --git a/build.gradle.kts b/build.gradle.kts index 561a7e3..c106aaf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id("fabric-loom") version "1.10-SNAPSHOT" + id("fabric-loom") version "1.11-SNAPSHOT" } -val targetVersion = findProperty("target_version") as String? ?: "1_21_4" +val targetVersion = findProperty("target_version") as String? ?: "1_21_10" val minecraftVersion = properties["minecraft_version_$targetVersion"] as String val yarnMappings = properties["yarn_mappings_$targetVersion"] as String val loaderVersion = properties["loader_version_$targetVersion"] as String diff --git a/gradle.properties b/gradle.properties index 37dfd46..1c59bee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx2G org.gradle.configuration-cache=true # Mod Global Properties -mod_version=1.1.2 +mod_version=1.1.6 maven_group=xyz.omegaware archives_base_name=OmegaWare Addons @@ -20,3 +20,8 @@ loader_version_1_21_4=0.16.14 minecraft_version_1_21_5=1.21.5 yarn_mappings_1_21_5=1.21.5+build.1 loader_version_1_21_5=0.16.14 + +# 1.21.10 Fabric Properties +minecraft_version_1_21_10=1.21.10 +yarn_mappings_1_21_10=1.21.10+build.2 +loader_version_1_21_10=0.17.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a79..ca025c8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/xyz/omegaware/addon/OmegawareAddons.java b/src/main/java/xyz/omegaware/addon/OmegawareAddons.java index 1eecd05..fb469c4 100644 --- a/src/main/java/xyz/omegaware/addon/OmegawareAddons.java +++ b/src/main/java/xyz/omegaware/addon/OmegawareAddons.java @@ -1,32 +1,27 @@ package xyz.omegaware.addon; import meteordevelopment.meteorclient.MeteorClient; -import meteordevelopment.meteorclient.commands.Commands; import meteordevelopment.meteorclient.pathing.BaritoneUtils; -import meteordevelopment.meteorclient.systems.hud.Hud; import meteordevelopment.meteorclient.utils.Utils; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.ModMetadata; -import xyz.omegaware.addon.commands.LinkCommand; -import xyz.omegaware.addon.commands.ShulkerQueueCommand; -import xyz.omegaware.addon.hud.OnlineTSRMembersHUD; -import xyz.omegaware.addon.modules.*; import com.mojang.logging.LogUtils; import meteordevelopment.meteorclient.addons.GithubRepo; import meteordevelopment.meteorclient.addons.MeteorAddon; -import meteordevelopment.meteorclient.systems.hud.HudGroup; import meteordevelopment.meteorclient.systems.modules.Category; import meteordevelopment.meteorclient.systems.modules.Modules; import org.slf4j.Logger; import java.io.File; +/** + * Slimmed-down addon entrypoint: only registers BetterBaritoneBuild. + */ public class OmegawareAddons extends MeteorAddon { public static final String MOD_ID = "omegaware-addons"; public static ModMetadata MOD_META; public static final Logger LOG = LogUtils.getLogger(); public static final Category CATEGORY = new Category("OmegaWare"); - public static final HudGroup HUD_GROUP = new HudGroup("OmegaWare"); public static File GetConfigFile(String key, String filename) { return new File(new File(new File(new File(MeteorClient.FOLDER, "omegaware"), key), Utils.getFileWorldName()), filename); @@ -34,29 +29,14 @@ public static File GetConfigFile(String key, String filename) { @Override public void onInitialize() { - LOG.info("Initializing OmegaWare Addons"); + LOG.info("Initializing OmegaWare Addons (pruned, BetterBaritoneBuild only)"); MOD_META = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().getMetadata(); - // Modules - Modules.get().add(new TPAAutomationModule()); - Modules.get().add(new BeaconRangeModule()); - Modules.get().add(new ChatFilterModule()); - Modules.get().add(new ItemFrameDupeModule()); - Modules.get().add(new BetterStashFinderModule()); - - if (FabricLoader.getInstance().isDevelopmentEnvironment()) { - Modules.get().add(new TSRKitBotModule()); // Is not ready yet - } - + // Only register the BetterBaritoneBuild module if Baritone is available. if (BaritoneUtils.IS_AVAILABLE) { - Modules.get().add(new BetterBaritoneBuild()); + Modules.get().add(new xyz.omegaware.addon.modules.BetterBaritoneBuild()); } - - Commands.add(new LinkCommand()); - Commands.add(new ShulkerQueueCommand()); - - Hud.get().register(OnlineTSRMembersHUD.INFO); } @Override @@ -74,9 +54,10 @@ public String getWebsite() { return "https://github.com/Omega172/OmegaWare-Addons"; } + // Update repo version tag to reflect Minecraft target (kept simple). @Override public GithubRepo getRepo() { - return new GithubRepo("Omega172", "OmegaWare-Addons", "1.21.4", null); + return new GithubRepo("Omega172", "OmegaWare-Addons", "1.21.10", null); } @Override diff --git a/src/main/java/xyz/omegaware/addon/commands/LinkCommand.java b/src/main/java/xyz/omegaware/addon/commands/LinkCommand.java deleted file mode 100644 index 859e581..0000000 --- a/src/main/java/xyz/omegaware/addon/commands/LinkCommand.java +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.omegaware.addon.commands; - -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import meteordevelopment.meteorclient.commands.Command; -import net.minecraft.command.CommandSource; -import xyz.omegaware.addon.modules.TSRKitBotModule; - -public class LinkCommand extends Command { - public LinkCommand() { - super("auth", "authorize with the KitBot api"); - } - - @Override - public void build(LiteralArgumentBuilder builder) { - builder.then(argument("2FACode", StringArgumentType.word()).executes(context -> { - TSRKitBotModule.getIsLinked(StringArgumentType.getString(context, "2FACode")); - return SINGLE_SUCCESS; - })); - } -} diff --git a/src/main/java/xyz/omegaware/addon/commands/ShulkerQueueCommand.java b/src/main/java/xyz/omegaware/addon/commands/ShulkerQueueCommand.java deleted file mode 100644 index 97feb78..0000000 --- a/src/main/java/xyz/omegaware/addon/commands/ShulkerQueueCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -package xyz.omegaware.addon.commands; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import meteordevelopment.meteorclient.commands.Command; -import net.minecraft.command.CommandSource; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Formatting; -import xyz.omegaware.addon.modules.ItemFrameDupeModule; -import xyz.omegaware.addon.utils.Logger; - -public class ShulkerQueueCommand extends Command { - public ShulkerQueueCommand() { - super("shulkerqueue", "add or remove items from the shulker queue"); - } - - @Override - public void build(LiteralArgumentBuilder builder) { - builder.then(literal("add").executes(context -> { - if (mc.player == null) { - Logger.error("Player was somehow null"); - return SINGLE_SUCCESS; - } - - ItemStack stack = mc.player.getMainHandStack(); - if (stack.isEmpty()) { - Logger.error("You must hold an item in your main hand"); - return SINGLE_SUCCESS; - } - ItemFrameDupeModule.shulkerQueue.add(stack.copy()); - - Logger.info("%sAdded %s to the shulker queue", Formatting.GREEN, stack.toHoverableText()); - - return SINGLE_SUCCESS; - })); - - builder.then(literal("remove").executes(context -> { - if (mc.player == null) { - Logger.error("Player was somehow null"); - return SINGLE_SUCCESS; - } - - ItemStack stack = mc.player.getMainHandStack(); - if (stack.isEmpty()) { - Logger.error("You must hold an item in your main hand"); - return SINGLE_SUCCESS; - } - if (!ItemFrameDupeModule.shulkerQueue.contains(stack.copy())) { - Logger.error("Item is not in the shulker queue"); - return SINGLE_SUCCESS; - } - - ItemFrameDupeModule.shulkerQueue.remove(stack.copy()); - - Logger.info("%sRemoved%s %s from the shulker queue", Formatting.RED, Formatting.WHITE ,stack.toHoverableText()); - return SINGLE_SUCCESS; - })); - - builder.then(literal("list").executes(context -> { - if (mc.player == null) { - Logger.error("Player was somehow null"); - return SINGLE_SUCCESS; - } - - if (ItemFrameDupeModule.shulkerQueue.isEmpty()) { - Logger.info("Shulker queue is empty"); - } else { - StringBuilder sb = new StringBuilder("Shulker queue: "); - ItemFrameDupeModule.shulkerQueue.forEach(itemStack -> sb.append(itemStack.toHoverableText().getString()).append("\n")); - Logger.info(sb.toString()); - } - - return SINGLE_SUCCESS; - })); - - builder.then(literal("clear").executes(context -> { - if (mc.player == null) { - Logger.error("Player was somehow null"); - - return SINGLE_SUCCESS; - } - - ItemFrameDupeModule.shulkerQueue.clear(); - - Logger.info("Cleared the shulker queue"); - - return SINGLE_SUCCESS; - })); - } -} diff --git a/src/main/java/xyz/omegaware/addon/hud/OnlineTSRMembersHUD.java b/src/main/java/xyz/omegaware/addon/hud/OnlineTSRMembersHUD.java deleted file mode 100644 index 1163f9a..0000000 --- a/src/main/java/xyz/omegaware/addon/hud/OnlineTSRMembersHUD.java +++ /dev/null @@ -1,141 +0,0 @@ -package xyz.omegaware.addon.hud; - -import com.google.common.util.concurrent.AtomicDouble; -import meteordevelopment.meteorclient.settings.BoolSetting; -import meteordevelopment.meteorclient.settings.Setting; -import meteordevelopment.meteorclient.settings.SettingGroup; -import meteordevelopment.meteorclient.systems.hud.HudElement; -import meteordevelopment.meteorclient.systems.hud.HudElementInfo; -import meteordevelopment.meteorclient.systems.hud.HudRenderer; -import meteordevelopment.meteorclient.utils.render.color.Color; -import xyz.omegaware.addon.OmegawareAddons; - -import java.util.ArrayList; -import java.util.List; - -import static meteordevelopment.meteorclient.MeteorClient.mc; - -public class OnlineTSRMembersHUD extends HudElement { - public static final HudElementInfo INFO = new HudElementInfo<>(OmegawareAddons.HUD_GROUP, "Online TSR Members", "Displays and overlay of all online TSR members", OnlineTSRMembersHUD::new); - - public OnlineTSRMembersHUD() { - super(INFO); - } - - private final SettingGroup sgGeneral = settings.getDefaultGroup(); - - public final Setting showSelf = sgGeneral.add(new BoolSetting.Builder() - .name("show-self") - .description("Whether to show yourself in the list.") - .defaultValue(false) - .build() - ); - - public final Setting showBots = sgGeneral.add(new BoolSetting.Builder() - .name("show-bots") - .description("Whether to show the kitbots in the list.") - .defaultValue(true) - .build() - ); - - private static class User { - String name; - String[] mcNames; - String rank; - - public User(String name, String[] mcNames, String rank) { - this.name = name; - this.mcNames = mcNames; - this.rank = rank; - } - } - - // Replace this with the api call when it is implemented - private final List tsrMembers = List.of( - new User("Bermani", new String[]{"Bermani"}, "Admin"), - new User("Slay", new String[]{"slay_dev"}, "Admin"), - new User("crystal", new String[]{""}, "Admin"), - new User("monstro", new String[]{""}, "Admin"), - new User("Pietty", new String[]{"Pietty"}, "Admin"), - new User("Omega", new String[]{"LostEmotions", "LostFriendships", "WomenAreScary", "ElectricCallboy"}, "OmegaWare"), - new User("Hastur", new String[]{"TheKingHastur", "chmoka90 "}, "Member"), - new User("J26V5", new String[]{"J26V5"}, "Member"), - new User("pyro", new String[]{""}, "Member"), - new User("Slyyy", new String[]{"TwoFresh4Yea"}, "Member"), - new User("_kingdom_warrior_", new String[]{"kingdom_warrior"}, "Member"), - new User("cerejo2", new String[]{"cerejo2", "cerejo222", "cerejo_2"}, "Member"), - new User("Emily", new String[]{""}, "Member"), - new User("heedi", new String[]{""}, "Member"), - new User("QUITTING ALL DAY", new String[]{"brunokumar12", "blinkyman1234", "brunokumar112"}, "Member"), - new User("StackedWithDonuts", new String[]{""}, "Member"), - new User("Z", new String[]{""}, "Member"), - new User("KitBot", new String[]{"royalburner", "Poolyin", "PoolyinHelper", "RoyalHelper", "TSRMANIA"}, "Bot") - ); - - @Override - public void render(HudRenderer renderer) { - if (mc.player == null) return; - //renderer.quad(x, y, getWidth(), getHeight(), Color.LIGHT_GRAY); - - // get all online players from tablist - List onlinePlayers = new ArrayList<>(mc.player.networkHandler.getPlayerList().stream().map(playerInfo -> playerInfo.getProfile().getName()).toList()); - - AtomicDouble screenY = new AtomicDouble(y+4); - - renderer.text(" Online TSR Members: ", x, screenY.get(), Color.RED, true); - screenY.addAndGet(renderer.textHeight(true)+1); - double storedY = screenY.get(); - screenY.addAndGet(5); - - AtomicDouble largestWidth = new AtomicDouble(renderer.textWidth("Online TSR Members: ", true)); - - onlinePlayers.forEach(player -> { - // Check if the player is a TSR member - tsrMembers.stream() - .filter(member -> member.mcNames.length > 0 && List.of(member.mcNames).contains(player)) - .findFirst() - .ifPresent(member -> { - if (!showBots.get() && member.rank.equals("Bot")) { - return; - } - - if (!showSelf.get() && member.mcNames[0].equals(mc.player.getName().getString())) { - return; - } - - // Render the member's name and rank - String displayText = " ["; - renderer.text(displayText, x, screenY.get(), Color.WHITE, true); - - Color color = switch (member.rank) { - case "Admin" -> Color.RED; - case "OmegaWare" -> Color.CYAN; - case "Member" -> Color.BLUE; - case "Bot" -> Color.GREEN; - default -> Color.WHITE; - }; - - renderer.text(member.rank, x + renderer.textWidth(displayText, true), screenY.get(), color, true); - displayText += member.rank; - renderer.text(String.format("] %s - %s", member.name, player), x + renderer.textWidth(displayText, true), screenY.get(), Color.WHITE, true); - displayText += String.format("] %s - %s", member.name, player); - - if (renderer.textWidth(displayText, true) > largestWidth.get()) { - largestWidth.set(renderer.textWidth(displayText, true)); - } - - screenY.addAndGet(renderer.textHeight(true) + 2); - }); - }); - - renderer.quad(x, y, largestWidth.get() + 4, screenY.get() - y, new Color(0, 0, 0, 150)); - renderer.line(x, storedY, x + largestWidth.get(), storedY, Color.LIGHT_GRAY); // Separator line - - renderer.line(x, y, x + largestWidth.get() + 4, y, Color.LIGHT_GRAY); // Top line - renderer.line(x, screenY.get(), x + largestWidth.get() + 4, screenY.get(), Color.LIGHT_GRAY); // Bottom line - renderer.line(x, y, x, screenY.get(), Color.LIGHT_GRAY); // Left line - renderer.line(x + largestWidth.get() + 4, y, x + largestWidth.get() + 4, screenY.get(), Color.LIGHT_GRAY); // Right line - - setSize(largestWidth.get() + 4, screenY.get() - y + 4); - } -} diff --git a/src/main/java/xyz/omegaware/addon/modules/BeaconRangeModule.java b/src/main/java/xyz/omegaware/addon/modules/BeaconRangeModule.java deleted file mode 100644 index 0ea92b8..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/BeaconRangeModule.java +++ /dev/null @@ -1,292 +0,0 @@ -package xyz.omegaware.addon.modules; - -import meteordevelopment.meteorclient.events.render.Render3DEvent; -import meteordevelopment.meteorclient.renderer.ShapeMode; -import meteordevelopment.meteorclient.settings.*; -import meteordevelopment.meteorclient.utils.Utils; -import meteordevelopment.meteorclient.utils.render.color.SettingColor; -import net.minecraft.block.Blocks; -import net.minecraft.block.entity.BeaconBlockEntity; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.world.World; -import xyz.omegaware.addon.OmegawareAddons; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.orbit.EventHandler; - -import java.util.ArrayList; -import java.util.List; - -public class BeaconRangeModule extends Module { - public BeaconRangeModule() { - super(OmegawareAddons.CATEGORY, "beacon-range", "A module that renders a box to show the range of powered beacons."); - } - - private final SettingGroup sgRender = settings.createGroup("Render"); - - private final Setting cullOverlapping = sgRender.add(new BoolSetting.Builder() - .name("cull-overlapping") - .description("Cull overlapping boxes.") - .defaultValue(true) - .build() - ); - - private final Setting shapeMode = sgRender.add(new EnumSetting.Builder() - .name("shape-mode") - .description("How the shapes are rendered.") - .defaultValue(ShapeMode.Both) - .visible(this::isActive) - .build() - ); - - private final Setting sideColor = sgRender.add(new ColorSetting.Builder() - .name("side-color") - .description("The side color of the rendering.") - .defaultValue(new SettingColor(0, 255, 255, 40)) - .visible(() -> shapeMode.get().sides()) - .build() - ); - - private final Setting lineColor = sgRender.add(new ColorSetting.Builder() - .name("line-color") - .description("The line color of the rendering.") - .defaultValue(new SettingColor(0, 255, 255, 255)) - .visible(() -> shapeMode.get().lines()) - .build() - ); - - private static class Rect2D { - double x1, y1, x2, y2; - Rect2D(double x1, double y1, double x2, double y2) { - this.x1 = Math.min(x1, x2); - this.y1 = Math.min(y1, y2); - this.x2 = Math.max(x1, x2); - this.y2 = Math.max(y1, y2); - } - boolean intersects(Rect2D o) { - return x1 < o.x2 && x2 > o.x1 && y1 < o.y2 && y2 > o.y1; - } - List subtract(Rect2D o) { - List out = new ArrayList<>(); - if (!intersects(o)) { - out.add(this); - return out; - } - // Top - if (y1 < o.y1) out.add(new Rect2D(x1, y1, x2, o.y1)); - // Bottom - if (y2 > o.y2) out.add(new Rect2D(x1, o.y2, x2, y2)); - // Left - if (x1 < o.x1) out.add(new Rect2D(x1, Math.max(y1, o.y1), o.x1, Math.min(y2, o.y2))); - // Right - if (x2 > o.x2) out.add(new Rect2D(o.x2, Math.max(y1, o.y1), x2, Math.min(y2, o.y2))); - return out; - } - } - - @EventHandler - private void onRender(Render3DEvent event) { - List renderedBoxes = new ArrayList<>(); - double epsilon = 0.001; - - for (BlockEntity blockEntity : Utils.blockEntities()) { - if (!(blockEntity instanceof BeaconBlockEntity)) continue; - - BlockPos pos = blockEntity.getPos(); - int level = getBeaconLevel(blockEntity.getWorld(), pos); - if (level < 1) continue; - - int range = 10 + (level * 10); - - double x1 = pos.getX() - range; - double y1 = pos.getY() - range; - double z1 = pos.getZ() - range; - double x2 = pos.getX() + range; - double y2 = pos.getY() + range; - double z2 = pos.getZ() + range; - - List toRender = new ArrayList<>(); - toRender.add(new Box(x1, y1, z1, x2, y2, z2)); - - if (cullOverlapping.get()) { - for (Box prev : renderedBoxes) { - List next = new ArrayList<>(); - for (Box box : toRender) { - next.addAll(subtractBox(box, prev)); - } - toRender = next; - if (toRender.isEmpty()) break; - } - } - - renderedBoxes.add(new Box(x1, y1, z1, x2, y2, z2)); - - // Per-face, per-section rendering - for (Box box : toRender) { - for (int axis = 0; axis < 3; axis++) { - for (boolean isMin : new boolean[]{true, false}) { - Rect2D faceRect; - double fx, fxE; - switch (axis) { - case 0: // X - fx = isMin ? box.minX : box.maxX; - faceRect = new Rect2D(box.minZ, box.minY, box.maxZ, box.maxY); - break; - case 1: // Y - fx = isMin ? box.minY : box.maxY; - faceRect = new Rect2D(box.minX, box.minZ, box.maxX, box.maxZ); - break; - case 2: // Z - fx = isMin ? box.minZ : box.maxZ; - faceRect = new Rect2D(box.minX, box.minY, box.maxX, box.maxY); - break; - default: continue; - } - List visible = new ArrayList<>(); - visible.add(faceRect); - for (Box other : renderedBoxes) { - if (other == box) break; // Only check previous boxes - boolean sharesFace = false; - Rect2D overlap = null; - switch (axis) { - case 0: - sharesFace = Math.abs((isMin ? other.maxX : other.minX) - fx) < 1e-6 && - other.minY < box.maxY && other.maxY > box.minY && - other.minZ < box.maxZ && other.maxZ > box.minZ; - if (sharesFace) overlap = new Rect2D( - Math.max(box.minZ, other.minZ), - Math.max(box.minY, other.minY), - Math.min(box.maxZ, other.maxZ), - Math.min(box.maxY, other.maxY) - ); - break; - case 1: - sharesFace = Math.abs((isMin ? other.maxY : other.minY) - fx) < 1e-6 && - other.minX < box.maxX && other.maxX > box.minX && - other.minZ < box.maxZ && other.maxZ > box.minZ; - if (sharesFace) overlap = new Rect2D( - Math.max(box.minX, other.minX), - Math.max(box.minZ, other.minZ), - Math.min(box.maxX, other.maxX), - Math.min(box.maxZ, other.maxZ) - ); - break; - case 2: - sharesFace = Math.abs((isMin ? other.maxZ : other.minZ) - fx) < 1e-6 && - other.minX < box.maxX && other.maxX > box.minX && - other.minY < box.maxY && other.maxY > box.minY; - if (sharesFace) overlap = new Rect2D( - Math.max(box.minX, other.minX), - Math.max(box.minY, other.minY), - Math.min(box.maxX, other.maxX), - Math.min(box.maxY, other.maxY) - ); - break; - } - if (sharesFace) { - List next = new ArrayList<>(); - for (Rect2D r : visible) next.addAll(r.subtract(overlap)); - visible = next; - if (visible.isEmpty()) break; - } - } - for (Rect2D r : visible) { - switch (axis) { - case 0: // X - fx = isMin ? box.minX : box.maxX; - fxE = isMin ? fx + epsilon : fx - epsilon; - event.renderer.box(fx, r.y1, r.x1, fxE, r.y2, r.x2, sideColor.get(), lineColor.get(), shapeMode.get(), 0); - break; - case 1: // Y - fx = isMin ? box.minY : box.maxY; - fxE = isMin ? fx + epsilon : fx - epsilon; - event.renderer.box(r.x1, fx, r.y1, r.x2, fxE, r.y2, sideColor.get(), lineColor.get(), shapeMode.get(), 0); - break; - case 2: // Z - fx = isMin ? box.minZ : box.maxZ; - fxE = isMin ? fx + epsilon : fx - epsilon; - event.renderer.box(r.x1, r.y1, fx, r.x2, r.y2, fxE, sideColor.get(), lineColor.get(), shapeMode.get(), 0); - break; - } - } - } - } - } - } - } - - private List subtractBox(Box box, Box subtract) { - List result = new ArrayList<>(); - if (!box.intersects(subtract)) { - result.add(box); - return result; - } - - double x1 = box.minX, y1 = box.minY, z1 = box.minZ; - double x2 = box.maxX, y2 = box.maxY, z2 = box.maxZ; - - double sx1 = subtract.minX, sy1 = subtract.minY, sz1 = subtract.minZ; - double sx2 = subtract.maxX, sy2 = subtract.maxY, sz2 = subtract.maxZ; - - // Left - if (x1 < sx1) - result.add(new Box(x1, y1, z1, sx1, y2, z2)); - // Right - if (x2 > sx2) - result.add(new Box(sx2, y1, z1, x2, y2, z2)); - // Bottom - if (y1 < sy1) - result.add(new Box(Math.max(x1, sx1), y1, z1, Math.min(x2, sx2), sy1, z2)); - // Top - if (y2 > sy2) - result.add(new Box(Math.max(x1, sx1), sy2, z1, Math.min(x2, sx2), y2, z2)); - // Front - if (z1 < sz1) - result.add(new Box(Math.max(x1, sx1), Math.max(y1, sy1), z1, Math.min(x2, sx2), Math.min(y2, sy2), sz1)); - // Back - if (z2 > sz2) - result.add(new Box(Math.max(x1, sx1), Math.max(y1, sy1), sz2, Math.min(x2, sx2), Math.min(y2, sy2), z2)); - - return result; - } - - public static int getBeaconLevel(World world, BlockPos beaconPos) { - int level = 0; - - for (int y = 1; y <= 4; y++) { - int layerY = beaconPos.getY() - y; - if (layerY < world.getBottomY()) break; - - boolean validLayer = true; - - for (int x = -y; x <= y; x++) { - for (int z = -y; z <= y; z++) { - BlockPos checkPos = beaconPos.add(x, -y, z); - if (!isValidBeaconBase(world, checkPos)) { - validLayer = false; - break; - } - } - if (!validLayer) break; - } - - if (validLayer) { - level++; - } else { - break; - } - } - - return level; - } - - private static boolean isValidBeaconBase(World world, BlockPos pos) { - return world.getBlockState(pos).isOf(Blocks.IRON_BLOCK) - || world.getBlockState(pos).isOf(Blocks.GOLD_BLOCK) - || world.getBlockState(pos).isOf(Blocks.EMERALD_BLOCK) - || world.getBlockState(pos).isOf(Blocks.DIAMOND_BLOCK) - || world.getBlockState(pos).isOf(Blocks.NETHERITE_BLOCK); - } - // End of BeaconCache -} diff --git a/src/main/java/xyz/omegaware/addon/modules/BetterBaritoneBuild.java b/src/main/java/xyz/omegaware/addon/modules/BetterBaritoneBuild.java index bc336fa..b38015f 100644 --- a/src/main/java/xyz/omegaware/addon/modules/BetterBaritoneBuild.java +++ b/src/main/java/xyz/omegaware/addon/modules/BetterBaritoneBuild.java @@ -13,7 +13,6 @@ import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.events.world.ServerConnectEndEvent; import meteordevelopment.meteorclient.events.world.TickEvent; -import meteordevelopment.meteorclient.gui.GuiTheme; import meteordevelopment.meteorclient.gui.widgets.WWidget; import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList; import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList; @@ -44,6 +43,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.Formatting; import xyz.omegaware.addon.OmegawareAddons; import xyz.omegaware.addon.utils.Logger; @@ -166,13 +166,25 @@ public BetterBaritoneBuild() { IBaritone baritone = null; + // safety/automation flags + private volatile boolean isFetching = false; + private long lastInteractMs = 0L; + private int openAttempts = 0; + private final long INTERACT_DEBOUNCE_MS = 800L; + private final int MAX_OPEN_ATTEMPTS = 6; + private final long AFTER_SHIFTCLICK_DELAY_MS = 80L; + + private BlockPos lastAutomatedInteractPos = null; + private long lastAutomatedInteractMs = 0L; + private boolean stuckPaused = false; + private static class LinkedStorage { public BlockPos blockPos; List inventory; public LinkedStorage() { - this.blockPos = BlockPos.ORIGIN; // Default position - this.inventory = new ArrayList<>(); // Default empty inventory + this.blockPos = BlockPos.ORIGIN; + this.inventory = new ArrayList<>(); } public LinkedStorage(BlockPos blockPos, List inventory) { @@ -191,7 +203,7 @@ public Event(boolean bWaitOnPath, Runnable callback) { this.callback = callback; } } - private final List eventQueue = new ArrayList<>(); + private final java.util.LinkedList eventQueue = new java.util.LinkedList<>(); private static class StorageItem { public Item item; @@ -208,6 +220,10 @@ public StorageItem(Item item, Integer stacks, LinkedStorage linkedStorage) { private String buildCommand = ""; + // NEW: store schematic name and explicit origin when user issues build + private BlockPos buildOrigin = null; + private String buildSchematicName = null; + @Override public void onActivate() { if (!BaritoneUtils.IS_AVAILABLE) { @@ -257,7 +273,7 @@ private void onRender(Render3DEvent event) { private BlockPos lastBlockPos = null; @Override - public WWidget getWidget(GuiTheme theme) { + public WWidget getWidget(meteordevelopment.meteorclient.gui.GuiTheme theme) { WVerticalList list = theme.verticalList(); WHorizontalList hList = list.add(theme.horizontalList()).expandX().widget(); @@ -301,11 +317,15 @@ private void onTickPre(TickEvent.Pre event) { Event queuedEvent = eventQueue.getFirst(); - if (queuedEvent.bWaitOnPath && baritone.getPathingBehavior().hasPath()) { + if (queuedEvent.bWaitOnPath && (baritone == null || baritone.getPathingBehavior().hasPath())) { return; } - queuedEvent.callback.run(); + try { + queuedEvent.callback.run(); + } catch (Exception e) { + if (debugMode.get()) Logger.warn("Exception while running queued event: %s", e.getMessage()); + } updateLinkedStorages(); @@ -319,15 +339,14 @@ private void onTickPost(TickEvent.Post event) { if (debugMode.get()) { Logger.info("%sPlayer is at home point.", Formatting.GREEN); } - ticksStuck = 0; // Reset the stuck counter if the player is at home - lastBlockPos = null; // Reset the last block position + ticksStuck = 0; + lastBlockPos = null; return; } if (home == null) { - // Yell at the player to set a home point Logger.error("Please set a home point using the \"Set Home\" button!"); - homeIfStuck.set(false); // Disable the setting if no home point is set + homeIfStuck.set(false); return; } @@ -342,7 +361,7 @@ private void onTickPost(TickEvent.Post event) { ticksStuck++; } else { ticksStuck = 0; - lastBlockPos = mc.player.getBlockPos(); // Update the last block position if the player has moved + lastBlockPos = mc.player.getBlockPos(); return; } @@ -351,23 +370,23 @@ private void onTickPost(TickEvent.Post event) { Logger.info("Should return home: %b", ticksStuck >= homeIfStuckTimeout.get() * 20); } - // 1 second = 20 ticks if (ticksStuck >= homeIfStuckTimeout.get() * 20) { Logger.error("Baritone is stuck, returning to home point..."); - ticksStuck = 0; // Reset the stuck counter - lastBlockPos = mc.player.getBlockPos(); // Update the last block position + ticksStuck = 0; + lastBlockPos = mc.player.getBlockPos(); eventQueue.clear(); itemsToFetch.clear(); - baritone.getPathingBehavior().cancelEverything(); + if (baritone != null) baritone.getPathingBehavior().cancelEverything(); - eventQueue.add(new Event(false, () -> baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(home)))); + stuckPaused = true; + eventQueue.add(new Event(false, () -> { + if (baritone != null) baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(home)); + })); - if (!buildCommand.isEmpty()) { - eventQueue.add(new Event(true, () -> baritone.getCommandManager().execute(buildCommand))); - } + Logger.info("Build paused due to stuck; re-issue build command manually when ready."); } } @@ -376,105 +395,147 @@ private void onMessageReceive(ReceiveMessageEvent event) { if (!isActive()) return; String msg = event.getMessage().getString(); if (msg == null || msg.isEmpty()) return; - msg = msg.toLowerCase().trim(); + msg = msg.trim(); - if (!msg.contains("[baritone]") || msg.contains("omegaware")) return; - int index = msg.indexOf("[baritone]"); + // We keep original logic but now capture origin + schematic name when user sends a build command. + String lower = msg.toLowerCase(); - msg = msg.substring(index+10).trim(); // Remove the "[Baritone]" part - // 10x block{minecraft:black_concrete}[axis=x] 86x block{minecraft:red_concrete} 1x block{minecraft:birch_log}[axis=y] - if (msg.matches("\\d+x block\\{minecraft:[a-z_]+}.*")) { - String[] parts = msg.split(" "); + // Baritone chat prefix messages: check and handle as before for missing items / done building + // Below is same logic for parsing [baritone] messages for fetching needs; keep original behavior + if (lower.contains("[baritone]") && !lower.contains("omegaware")) { + // handle baritone output messages (fetch items / done) -- unchanged + int index = lower.indexOf("[baritone]"); + String inner = lower.substring(index + 10).trim(); - String blockCount = parts[0].replace("x", "").trim(); - int count = Integer.parseInt(blockCount); - int stacks = (int) Math.ceil(count / 64.0); + // If message is like "10x block{minecraft:stone} ..." -> request to fetch items + if (inner.matches("\\d+x block\\{minecraft:[a-z_]+}.*")) { + String[] parts = inner.split(" "); - String blockMessage = parts[1]; - String blockName = blockMessage.substring(blockMessage.indexOf(':') + 1); + String blockCount = parts[0].replace("x", "").trim(); + int count = Integer.parseInt(blockCount); + int stacks = (int) Math.ceil(count / 64.0); - int endIndex = blockName.indexOf('}'); - if (endIndex != -1) { - blockName = blockName.substring(0, endIndex); - } + String blockMessage = parts[1]; + String blockName = blockMessage.substring(blockMessage.indexOf(':') + 1); + + int endIndex = blockName.indexOf('}'); + if (endIndex != -1) { + blockName = blockName.substring(0, endIndex); + } - Identifier identifier = Identifier.of(blockName); - Item item = Registries.ITEM.get(identifier).asItem(); + Identifier identifier = Identifier.of(blockName); + Item item = Registries.ITEM.get(identifier).asItem(); - if (item == null) { - if (debugMode.get()) Logger.error("Item not found: %s%s", Formatting.WHITE, blockName); - return; - } + if (item == null) { + if (debugMode.get()) Logger.error("Item not found: %s%s", Formatting.WHITE, blockName); + return; + } - if (itemsToFetch.stream().anyMatch(storageItem -> storageItem.item.equals(item))) { - if (debugMode.get()) { - Logger.warn("Item already in queue: %s%s", Formatting.WHITE, item.getName().getString()); + if (itemsToFetch.stream().anyMatch(storageItem -> storageItem.item.equals(item))) { + if (debugMode.get()) { + Logger.warn("Item already in queue: %s%s", Formatting.WHITE, item.getName().getString()); + } + return; } + + LinkedStorage linkedStorage = findItem(item); + if (linkedStorage == null) { + Logger.error("No linked storage contains the item: %s%s", Formatting.WHITE, item.getName().getString()); + + if (disconnectOnError.get()) { + AutoReconnect autoReconnect = Modules.get().get(meteordevelopment.meteorclient.systems.modules.misc.AutoReconnect.class); + if (autoReconnect != null && autoReconnect.isActive()) { + autoReconnect.toggle(); + } + + String prefix = Logger.PREFIX.getString(); + MutableText text = Text.literal(String.format("%s%s%s%s %s", Formatting.GRAY, Formatting.BLUE, prefix.substring(0, prefix.length() - 1), Formatting.GRAY, Formatting.RED) + String.format("No linked storage contains the item: %s\n", item.getName().getString())); + + disconnectOnError.set(false); + + ClientPlayNetworkHandler networkHandler = mc.getNetworkHandler(); + if (networkHandler != null) { + networkHandler.getConnection().disconnect(text); + } + } + + return; + } + + itemsToFetch.add(new StorageItem(item, stacks + extraStacks.get(), linkedStorage)); + + // If build was paused due to stuck, consider that a user intent to continue -> clear pause + stuckPaused = false; + + pathToLinkedStorage(item, linkedStorage); return; } - LinkedStorage linkedStorage = findItem(item); - if (linkedStorage == null) { - Logger.error("No linked storage contains the item: %s%s", Formatting.WHITE, item.getName().getString()); + if (inner.contains("done building")) { + if (debugMode.get()) { + Logger.info("Baritone has finished building!"); + } - if (disconnectOnError.get()) { + if (disconnectOnDone.get()) { AutoReconnect autoReconnect = Modules.get().get(meteordevelopment.meteorclient.systems.modules.misc.AutoReconnect.class); - if (autoReconnect.isActive()) { + if (autoReconnect != null && autoReconnect.isActive()) { autoReconnect.toggle(); } String prefix = Logger.PREFIX.getString(); - MutableText text = Text.literal(String.format("%s%s%s%s %s", Formatting.GRAY, Formatting.BLUE, prefix.substring(0, prefix.length() - 1), Formatting.GRAY, Formatting.RED) + String.format("No linked storage contains the item: %s\n", item.getName().getString())); - - disconnectOnError.set(false); // Disable the setting to prevent infinite disconnects + MutableText text = Text.literal(String.format("%s%s%s%s %s", Formatting.GRAY, Formatting.BLUE, prefix.substring(0, prefix.length() - 1), Formatting.GRAY, Formatting.RED) + "Baritone has finished building!"); ClientPlayNetworkHandler networkHandler = mc.getNetworkHandler(); if (networkHandler != null) { networkHandler.getConnection().disconnect(text); } } - return; } - itemsToFetch.add(new StorageItem(item, stacks + extraStacks.get(), linkedStorage)); - - pathToLinkedStorage(item, linkedStorage); return; } - if (msg.contains("done building")) { - if (debugMode.get()) { - Logger.info("Baritone has finished building!"); - } - - if (disconnectOnDone.get()) { - AutoReconnect autoReconnect = Modules.get().get(meteordevelopment.meteorclient.systems.modules.misc.AutoReconnect.class); - if (autoReconnect.isActive()) { - autoReconnect.toggle(); - } - - String prefix = Logger.PREFIX.getString(); - MutableText text = Text.literal(String.format("%s%s%s%s %s", Formatting.GRAY, Formatting.BLUE, prefix.substring(0, prefix.length() - 1), Formatting.GRAY, Formatting.RED) + "Baritone has finished building!"); - - ClientPlayNetworkHandler networkHandler = mc.getNetworkHandler(); - if (networkHandler != null) { - networkHandler.getConnection().disconnect(text); + // Normal chat capture for build commands - we capture origin + schematic name + String trimmed = msg.trim(); + String lowerTrim = trimmed.toLowerCase(); + + // remove leading chat prompt if present: many clients use "> build ..." or just "build ..." + String plain = trimmed; + if (plain.startsWith("> ")) plain = plain.substring(2).trim(); + + if (plain.toLowerCase().startsWith("build ") || plain.toLowerCase().startsWith("litematica ") || plain.toLowerCase().startsWith("lbuild ") || plain.toLowerCase().startsWith("schematic ") ) { + buildCommand = plain; + // capture origin and schematic name if possible + if (mc.player != null) { + buildOrigin = mc.player.getBlockPos(); + } else buildOrigin = null; + + // try to extract schematic name (first token after command) + String[] tokens = plain.split("\\s+"); + String name = null; + if (tokens.length >= 2) { + // e.g. "build test.schematic" -> tokens[1] = "test.schematic" + name = tokens[1].trim(); + // strip any surrounding quotes + if ((name.startsWith("\"") && name.endsWith("\"")) || (name.startsWith("'") && name.endsWith("'"))) { + name = name.substring(1, name.length() - 1); } } - return; - } + buildSchematicName = name; + + // If user explicitly sent a build, clear stuck pause + stuckPaused = false; - msg = msg.substring(2).trim(); // Remove the "> " part - if (msg.startsWith("build") || msg.startsWith("litematica")) { - buildCommand = msg; if (debugMode.get()) { - Logger.info("Build command captured: %s%s", Formatting.WHITE, buildCommand); + Logger.info("Captured build command: %s, schematic=%s, origin=%s", buildCommand, buildSchematicName, buildOrigin == null ? "null" : String.format("X=%d,Y=%d,Z=%d", buildOrigin.getX(), buildOrigin.getY(), buildOrigin.getZ())); } return; } - if (msg.startsWith("stop") || msg.startsWith("cancel")) { + // stop/cancel command handling + String lowerPlain = plain.toLowerCase(); + if (lowerPlain.startsWith("stop") || lowerPlain.startsWith("cancel")) { buildCommand = ""; eventQueue.clear(); itemsToFetch.clear(); @@ -493,67 +554,73 @@ private void onBlockInteract(InteractBlockEvent event) { if (!isActive() || mc.world == null || !storageLinkMode.get()) return; lastBlockInteractPos = event.result.getBlockPos(); + lastAutomatedInteractPos = null; } @EventHandler private void onInventory(InventoryEvent event) { - if (!isActive() || mc.player == null || mc.world == null || mc.currentScreen == null) return; - - if (!itemsToFetch.isEmpty()) { - itemsToFetch.forEach(storageItem -> MeteorExecutor.execute(() -> { - if (debugMode.get()) { - String msg = String.format("Fetching %s stacks of %s from linked storage at X=%s, Y=%s, Z=%s", storageItem.stacks, storageItem.item.getName().getString(), storageItem.linkedStorage.blockPos.getX(), storageItem.linkedStorage.blockPos.getY(), storageItem.linkedStorage.blockPos.getZ()); - Logger.info(msg); + if (!isActive() || mc.player == null || mc.world == null) return; + + if (!itemsToFetch.isEmpty() && !isFetching) { + StorageItem itemToProcess = itemsToFetch.get(0); + + isFetching = true; + MeteorExecutor.execute(() -> { + try { + moveSlots(itemToProcess, mc.player.currentScreenHandler); + } finally { + try { Thread.sleep(120); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } + isFetching = false; } - moveSlots(storageItem, mc.player.currentScreenHandler); - })); + }); } + if (mc.currentScreen == null) return; if (lastBlockInteractPos == null) return; + + if (lastAutomatedInteractPos != null && lastBlockInteractPos.equals(lastAutomatedInteractPos) + && (System.currentTimeMillis() - lastAutomatedInteractMs) < 5000L) { + lastBlockInteractPos = null; + return; + } + BlockEntity blockEntity = mc.world.getBlockEntity(lastBlockInteractPos); - if (blockEntity == null) return; + if (blockEntity == null) { + lastBlockInteractPos = null; + return; + } - for (LinkedStorage linkedStorage : linkedStorages) { + boolean handled = false; + for (int i = 0; i < linkedStorages.size(); i++) { + LinkedStorage linkedStorage = linkedStorages.get(i); if (linkedStorage.blockPos.equals(lastBlockInteractPos)) { lastBlockInteractPos = null; - linkedStorages.remove(linkedStorage); + linkedStorages.remove(i); LinkedStorage newStorage = indexStorage(mc.player.currentScreenHandler, blockEntity.getPos()); if (newStorage != null) { linkedStorages.add(newStorage); saveLinkedStorages(); + Logger.info("Updated linked storage at X=%s, Y=%s, Z=%s", blockEntity.getPos().getX(), blockEntity.getPos().getY(), blockEntity.getPos().getZ()); } - - return; + handled = true; + break; } } + if (handled) return; - if (!storageLinkMode.get()) return; - if (blockEntity instanceof ShulkerBoxBlockEntity || blockEntity instanceof ChestBlockEntity || blockEntity instanceof BarrelBlockEntity || blockEntity instanceof EnderChestBlockEntity) { - for (LinkedStorage linkedStorage : linkedStorages) { - if (linkedStorage.blockPos.equals(lastBlockInteractPos)) { - lastBlockInteractPos = null; - linkedStorages.remove(linkedStorage); - - LinkedStorage newStorage = indexStorage(mc.player.currentScreenHandler, blockEntity.getPos()); - if (newStorage == null) return; + if (!storageLinkMode.get()) { lastBlockInteractPos = null; return; } - linkedStorages.add(newStorage); - saveLinkedStorages(); - } - } + if (blockEntity instanceof ShulkerBoxBlockEntity || blockEntity instanceof ChestBlockEntity || blockEntity instanceof BarrelBlockEntity || blockEntity instanceof EnderChestBlockEntity) { + LinkedStorage newStorage = indexStorage(mc.player.currentScreenHandler, blockEntity.getPos()); lastBlockInteractPos = null; - - LinkedStorage linkedStorage = indexStorage(mc.player.currentScreenHandler, blockEntity.getPos()); - if (linkedStorage == null) return; - - if (linkedStorage.inventory.isEmpty()) { + if (newStorage == null) return; + if (newStorage.inventory.isEmpty()) { if (debugMode.get()) Logger.error("No items found in the linked storage!"); return; } - linkedStorages.add(linkedStorage); + linkedStorages.add(newStorage); saveLinkedStorages(); - Logger.info("Linked Storage located at X=%s, Y=%s, Z=%s", blockEntity.getPos().getX(), blockEntity.getPos().getY(), blockEntity.getPos().getZ()); } } @@ -601,7 +668,6 @@ private void saveLinkedStorages() { private void loadLinkedStorages() { File configFile = OmegawareAddons.GetConfigFile("better-build", "linked_storages.json"); if (!configFile.exists()) { - //noinspection LoggingSimilarMessage OmegawareAddons.LOG.warn("{} not found!", configFile.toPath()); return; } @@ -702,7 +768,7 @@ private LinkedStorage indexStorage(ScreenHandler screenHandler, BlockPos blockPo if (screenHandler == null) return null; LinkedStorage linkedStorage = new LinkedStorage(blockPos, new ArrayList<>()); - for (int i = 0; i < SlotUtils.indexToId(SlotUtils.MAIN_START); i++) { + for (int i = 0; i < SlotUtils.indexToId(SlotUtils.MAIN_START) && i < screenHandler.slots.size(); i++) { ItemStack stack = screenHandler.getSlot(i).getStack(); if (!stack.isEmpty()) { linkedStorage.inventory.add(stack.copy()); @@ -717,21 +783,21 @@ private void pathToPos(BlockPos blockPos) { if (debugMode.get()) Logger.info("%sNavigating to:%s X=%s, Y=%s, Z=%s", Formatting.GREEN, Formatting.WHITE, blockPos.getX(), blockPos.getY(), blockPos.getZ()); - if (!ignoreY.get()) { - baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(blockPos)); - } else baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(blockPos.withY(mc.player.getBlockY()))); + if (baritone != null) baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(blockPos)); + } else { + BlockPos target = new BlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + if (baritone != null) baritone.getCustomGoalProcess().setGoalAndPath(new GoalGetToBlock(target)); + } } private LinkedStorage findItem(Item item) { - // Sort the linked storages by distance to the player if (mc.player == null || mc.world == null) return null; linkedStorages.sort((a, b) -> { double distanceA = a.blockPos.getSquaredDistance(mc.player.getBlockPos()); double distanceB = b.blockPos.getSquaredDistance(mc.player.getBlockPos()); return Double.compare(distanceA, distanceB); }); - // Iterate through the linked storages and check if the item is present in any of them for (LinkedStorage linkedStorage : linkedStorages) { for (ItemStack stack : linkedStorage.inventory) { if (stack.getItem() == item) { @@ -744,31 +810,80 @@ private LinkedStorage findItem(Item item) { } private void pathToLinkedStorage(Item item, LinkedStorage linkedStorage) { - if (mc.player == null || mc.interactionManager == null) return; + if (mc.player == null || mc.interactionManager == null || linkedStorage == null) return; Logger.info("%sNavigating to storage containing:%s %s", Formatting.GREEN, Formatting.WHITE, item.getName().getString()); + openAttempts = 0; + eventQueue.add(new Event(true, () -> pathToPos(linkedStorage.blockPos))); eventQueue.add(new Event(true, () -> { - mc.setScreen(null); // Close any open screens to ensure that we can interact with the storage block - - Vec3d hitPos = Vec3d.ofCenter(linkedStorage.blockPos); - BlockHitResult hit = new BlockHitResult(hitPos, Direction.UP, linkedStorage.blockPos, false); + long now = System.currentTimeMillis(); + if (now - lastInteractMs < INTERACT_DEBOUNCE_MS) { + if (debugMode.get()) Logger.warn("Interact debounced, skipping immediate interact (delta=%dms)", now - lastInteractMs); + MeteorExecutor.execute(() -> { + try { Thread.sleep(INTERACT_DEBOUNCE_MS); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } + eventQueue.add(new Event(true, () -> { + performStorageInteractSafely(linkedStorage); + })); + }); + return; + } - ActionResult result = mc.interactionManager.interactBlock(mc.player, Hand.MAIN_HAND, hit); // Attempt to interact with the block - if (result.isAccepted()) // If the interaction was successful, we can then make the player swing their hand - mc.player.swingHand(Hand.MAIN_HAND); + performStorageInteractSafely(linkedStorage); })); } + private void performStorageInteractSafely(LinkedStorage linkedStorage) { + if (mc.player == null || mc.interactionManager == null || linkedStorage == null) return; + + if (openAttempts >= MAX_OPEN_ATTEMPTS) { + Logger.error("Too many open attempts for storage at X=%s, Y=%s, Z=%s. Aborting fetch.", linkedStorage.blockPos.getX(), linkedStorage.blockPos.getY(), linkedStorage.blockPos.getZ()); + eventQueue.clear(); + itemsToFetch.clear(); + openAttempts = 0; + return; + } + + mc.setScreen(null); + + Vec3d hitPos = Vec3d.ofCenter(linkedStorage.blockPos); + BlockHitResult hit = new BlockHitResult(hitPos, Direction.UP, linkedStorage.blockPos, false); + + ActionResult result = mc.interactionManager.interactBlock(mc.player, Hand.MAIN_HAND, hit); + lastInteractMs = System.currentTimeMillis(); + openAttempts++; + + if (result.isAccepted()) { + mc.player.swingHand(Hand.MAIN_HAND); + lastAutomatedInteractPos = linkedStorage.blockPos; + lastAutomatedInteractMs = System.currentTimeMillis(); + + if (debugMode.get()) Logger.info("Interact accepted (attempt #%d)", openAttempts); + } else { + if (debugMode.get()) Logger.warn("Interact not accepted (attempt #%d), result=%s", openAttempts, result.toString()); + } + } + private void moveSlots(StorageItem storageItem, ScreenHandler handler) { if (mc.player == null) return; + if (storageItem == null) return; + boolean initial = true; int count = 0; + List grabbedItems = new ArrayList<>(); - for (int i = 0; i < SlotUtils.MAIN_END; i++) { + + if (handler == null) { + if (debugMode.get()) Logger.warn("moveSlots: no open screen handler to move items from."); + return; + } + + int maxIndex = Math.min(SlotUtils.MAIN_END, handler.slots.size()); + + for (int i = 0; i < maxIndex; i++) { if (!handler.getSlot(i).hasStack()) continue; int sleep; @@ -783,7 +898,6 @@ private void moveSlots(StorageItem storageItem, ScreenHandler handler) { OmegawareAddons.LOG.error("Interrupted while sleeping in moveSlots: {}", e.getMessage()); } - // Exit if user closes screen or exit world if (mc.currentScreen == null || !Utils.canUpdate()) break; Item item = handler.getSlot(i).getStack().getItem(); @@ -792,33 +906,78 @@ private void moveSlots(StorageItem storageItem, ScreenHandler handler) { grabbedItems.add(item); LinkedStorage linkedStorage = storageItem.linkedStorage; - linkedStorages.remove(linkedStorage); - int finalI = i; - linkedStorage.inventory.removeIf(itemStack -> itemStack.equals(handler.getSlot(finalI).getStack())); - linkedStorages.add(linkedStorage); - saveLinkedStorages(); + if (linkedStorage != null) { + for (int si = 0; si < linkedStorages.size(); si++) { + LinkedStorage ls = linkedStorages.get(si); + if (ls.blockPos.equals(linkedStorage.blockPos)) { + ItemStack stackInSlot = handler.getSlot(i).getStack(); + linkedStorages.get(si).inventory.removeIf(itemStack -> itemStack.getItem() == stackInSlot.getItem()); + break; + } + } + saveLinkedStorages(); + } count++; InvUtils.shiftClick().slotId(i); + try { Thread.sleep(AFTER_SHIFTCLICK_DELAY_MS); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } + if (count >= storageItem.stacks) { break; } } - itemsToFetch.remove(storageItem); + int remaining = Math.max(0, storageItem.stacks - count); + + itemsToFetch.removeIf(si -> { + if (si.item == storageItem.item) { + if (si.linkedStorage == null && storageItem.linkedStorage == null) return true; + if (si.linkedStorage != null && storageItem.linkedStorage != null && si.linkedStorage.blockPos.equals(storageItem.linkedStorage.blockPos)) + return true; + } + return false; + }); + + if (remaining > 0) { + StorageItem newItem = new StorageItem(storageItem.item, remaining, storageItem.linkedStorage); + itemsToFetch.add(0, newItem); + } - storageItem.stacks = storageItem.stacks - count; - itemsToFetch.add(storageItem); + if (mc != null) { + MinecraftClient.getInstance().execute(() -> { + try { + if (mc.currentScreen != null) mc.setScreen(null); + } catch (Exception ignored) { } + }); + } - int finalCount = count; - itemsToFetch.removeIf(element -> grabbedItems.contains(element.item) && finalCount >= element.stacks); + lastAutomatedInteractPos = null; + lastAutomatedInteractMs = 0L; if (!itemsToFetch.isEmpty()) { + StorageItem next = itemsToFetch.get(0); eventQueue.clear(); - itemsToFetch.forEach(element -> pathToLinkedStorage(element.item, element.linkedStorage)); + pathToLinkedStorage(next.item, next.linkedStorage); } else if (!buildCommand.isEmpty()) { - eventQueue.add(new Event(true, () -> baritone.getCommandManager().execute(buildCommand))); + if (!stuckPaused) { + // NEW: Prefer explicit Baritone API call with stored origin, if available + if (baritone != null && buildSchematicName != null && buildOrigin != null) { + try { + if (debugMode.get()) Logger.info("Resuming build using Baritone API with explicit origin: %s", buildOrigin); + // Use Baritone builder process with explicit origin (prevents anchor drift) + baritone.getBuilderProcess().build(buildSchematicName, buildOrigin); + } catch (Exception e) { + // fallback to sending raw command if API fails + if (debugMode.get()) Logger.error("Failed to use builder API (fallback to command): %s", e.getMessage()); + eventQueue.add(new Event(true, () -> baritone.getCommandManager().execute(buildCommand))); + } + } else if (baritone != null) { + eventQueue.add(new Event(true, () -> baritone.getCommandManager().execute(buildCommand))); + } + } else { + Logger.info("Build remains paused (home-if-stuck triggered earlier). Re-issue build command to resume."); + } } } } diff --git a/src/main/java/xyz/omegaware/addon/modules/BetterStashFinderModule.java b/src/main/java/xyz/omegaware/addon/modules/BetterStashFinderModule.java deleted file mode 100644 index a45e47a..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/BetterStashFinderModule.java +++ /dev/null @@ -1,348 +0,0 @@ -package xyz.omegaware.addon.modules; - -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import meteordevelopment.meteorclient.events.world.ChunkDataEvent; -import meteordevelopment.meteorclient.gui.GuiTheme; -import meteordevelopment.meteorclient.gui.WindowScreen; -import meteordevelopment.meteorclient.gui.widgets.WWidget; -import meteordevelopment.meteorclient.gui.widgets.containers.WTable; -import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList; -import meteordevelopment.meteorclient.gui.widgets.pressable.WButton; -import meteordevelopment.meteorclient.gui.widgets.pressable.WMinus; -import meteordevelopment.meteorclient.pathing.PathManagers; -import meteordevelopment.meteorclient.settings.*; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.meteorclient.systems.modules.Modules; -import meteordevelopment.meteorclient.systems.modules.misc.AutoReconnect; -import meteordevelopment.meteorclient.systems.modules.world.StashFinder; -import meteordevelopment.meteorclient.utils.render.MeteorToast; -import meteordevelopment.orbit.EventHandler; -import net.minecraft.block.entity.*; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.item.Items; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import xyz.omegaware.addon.OmegawareAddons; -import xyz.omegaware.addon.utils.Logger; - -import java.io.*; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -// A straight-up copy of Meteors StashFinder, but with some slight changes. -public class BetterStashFinderModule extends Module { - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - - private final SettingGroup sgGeneral = settings.getDefaultGroup(); - - private final Setting>> storageBlocks = sgGeneral.add(new StorageBlockListSetting.Builder() - .name("storage-blocks") - .description("Select the storage blocks to search for.") - .defaultValue(StorageBlockListSetting.STORAGE_BLOCKS) - .build() - ); - - private final Setting minimumStorageCount = sgGeneral.add(new IntSetting.Builder() - .name("minimum-storage-count") - .description("The minimum amount of storage blocks in a chunk to record the chunk.") - .defaultValue(50) - .min(1) - .sliderMin(1) - .sliderMax(1024) - .build() - ); - - private final Setting minimumDistance = sgGeneral.add(new IntSetting.Builder() - .name("minimum-distance") - .description("The minimum distance you must be from spawn to record a certain chunk.") - .defaultValue(0) - .min(0) - .sliderMax(10000) - .build() - ); - - private final Setting sendNotifications = sgGeneral.add(new BoolSetting.Builder() - .name("notifications") - .description("Sends Minecraft notifications when new stashes are found.") - .defaultValue(true) - .build() - ); - - private final Setting notificationMode = sgGeneral.add(new EnumSetting.Builder() - .name("notification-mode") - .description("The mode to use for notifications.") - .defaultValue(StashFinder.Mode.Both) - .visible(sendNotifications::get) - .build() - ); - - private final Setting disconnectOnStashFound = sgGeneral.add(new BoolSetting.Builder() - .name("disconnect-on-stash-found") - .description("Disconnects you from the server when a stash is found.") - .defaultValue(false) - .build() - ); - - public List chunks = new ArrayList<>(); - - public BetterStashFinderModule() { - super(OmegawareAddons.CATEGORY, "better-stash-finder", "Searches loaded chunks for storage blocks. Saves to /meteor-client"); - } - - @Override - public void onActivate() { - load(); - } - - @EventHandler - private void onChunkData(ChunkDataEvent event) { - // Check the distance. - double chunkXAbs = Math.abs(event.chunk().getPos().x * 16); - double chunkZAbs = Math.abs(event.chunk().getPos().z * 16); - if (Math.sqrt(chunkXAbs * chunkXAbs + chunkZAbs * chunkZAbs) < minimumDistance.get()) return; - - StashFinder.Chunk chunk = new StashFinder.Chunk(event.chunk().getPos()); - - for (BlockEntity blockEntity : event.chunk().getBlockEntities().values()) { - if (!storageBlocks.get().contains(blockEntity.getType())) continue; - - //noinspection IfCanBeSwitch - if (blockEntity instanceof ChestBlockEntity) chunk.chests++; - else if (blockEntity instanceof BarrelBlockEntity) chunk.barrels++; - else if (blockEntity instanceof ShulkerBoxBlockEntity) chunk.shulkers++; - else if (blockEntity instanceof EnderChestBlockEntity) chunk.enderChests++; - else if (blockEntity instanceof AbstractFurnaceBlockEntity) chunk.furnaces++; - else if (blockEntity instanceof DispenserBlockEntity) chunk.dispensersDroppers++; - else if (blockEntity instanceof HopperBlockEntity) chunk.hoppers++; - } - - if (chunk.getTotal() >= minimumStorageCount.get()) { - StashFinder.Chunk prevChunk = null; - int i = chunks.indexOf(chunk); - - if (i < 0) chunks.add(chunk); - else prevChunk = chunks.set(i, chunk); - - saveJson(); - saveCsv(); - - if (sendNotifications.get() && (!chunk.equals(prevChunk) || !chunk.countsEqual(prevChunk))) { - switch (notificationMode.get()) { - case Chat -> info("Found stash at (highlight)%s(default), (highlight)%s(default).", chunk.x, chunk.z); - case Toast -> mc.getToastManager().add(new MeteorToast(Items.CHEST, title, "Found Stash!")); - case Both -> { - info("Found stash at (highlight)%s(default), (highlight)%s(default).", chunk.x, chunk.z); - mc.getToastManager().add(new MeteorToast(Items.CHEST, title, "Found Stash!")); - } - } - } - - if (disconnectOnStashFound.get()) { - AutoReconnect autoReconnect = Modules.get().get(meteordevelopment.meteorclient.systems.modules.misc.AutoReconnect.class); - if (autoReconnect.isActive()) { - autoReconnect.toggle(); - } - - String prefix = Logger.PREFIX.getString(); - MutableText text = Text.literal(String.format("%s%s%s%s %s", Formatting.GRAY, Formatting.BLUE, prefix.substring(0, prefix.length() - 1), Formatting.GRAY, Formatting.RED) + String.format("Found stash at %s, %s.", chunk.x, chunk.z)).append("\n"); - - disconnectOnStashFound.set(false); // Disable the setting to prevent infinite disconnects - - ClientPlayNetworkHandler networkHandler = mc.getNetworkHandler(); - if (networkHandler != null) { - networkHandler.getConnection().disconnect(text); - } - } - } - } - - @Override - public WWidget getWidget(GuiTheme theme) { - // Sort - chunks.sort(Comparator.comparingInt(value -> -value.getTotal())); - - WVerticalList list = theme.verticalList(); - - // Clear - WButton clear = list.add(theme.button("Clear")).widget(); - - WTable table = new WTable(); - if (!chunks.isEmpty()) list.add(table); - - clear.action = () -> { - chunks.clear(); - table.clear(); - }; - - // Chunks - fillTable(theme, table); - - return list; - } - - private void fillTable(GuiTheme theme, WTable table) { - for (StashFinder.Chunk chunk : chunks) { - table.add(theme.label("Pos: " + chunk.x + ", " + chunk.z)); - table.add(theme.label("Total: " + chunk.getTotal())); - - WButton open = table.add(theme.button("Open")).widget(); - open.action = () -> mc.setScreen(new ChunkScreen(theme, chunk)); - - WButton gotoBtn = table.add(theme.button("Goto")).widget(); - gotoBtn.action = () -> PathManagers.get().moveTo(new BlockPos(chunk.x, 0, chunk.z), true); - - WMinus delete = table.add(theme.minus()).widget(); - delete.action = () -> { - if (chunks.remove(chunk)) { - table.clear(); - fillTable(theme, table); - - saveJson(); - saveCsv(); - } - }; - - table.row(); - } - } - - private void saveCsv() { - try { - File file = OmegawareAddons.GetConfigFile("better-stash-finder", "stashes.csv"); - //noinspection ResultOfMethodCallIgnored - file.getParentFile().mkdirs(); - Writer writer = new FileWriter(file); - - writer.write("X,Z,Chests,Barrels,Shulkers,EnderChests,Furnaces,DispensersDroppers,Hoppers\n"); - for (StashFinder.Chunk chunk : chunks) chunk.write(writer); - - writer.close(); - } catch (IOException e) { - OmegawareAddons.LOG.info("Failed to save stashes to CSV: {}", e.getMessage()); - } - } - - private void saveJson() { - try { - File file = OmegawareAddons.GetConfigFile("better-stash-finder", "stashes.json"); - //noinspection ResultOfMethodCallIgnored - file.getParentFile().mkdirs(); - Writer writer = new FileWriter(file); - GSON.toJson(chunks, writer); - writer.close(); - } catch (IOException e) { - OmegawareAddons.LOG.info("Failed to save stashes to JSON: {}", e.getMessage()); - } - } - - private void load() { - boolean loaded = false; - - // Try to load json - File file = OmegawareAddons.GetConfigFile("better-stash-finder", "stashes.json"); - if (file.exists()) { - try { - FileReader reader = new FileReader(file); - chunks = GSON.fromJson(reader, new TypeToken>() {}.getType()); - reader.close(); - - for (StashFinder.Chunk chunk : chunks) chunk.calculatePos(); - - loaded = true; - } catch (Exception ignored) { - if (chunks == null) chunks = new ArrayList<>(); - } - } - - // Try to load csv - file = OmegawareAddons.GetConfigFile("better-stash-finder", "stashes.csv"); - if (!loaded && file.exists()) { - try { - BufferedReader reader = new BufferedReader(new FileReader(file)); - reader.readLine(); - - String line; - while ((line = reader.readLine()) != null) { - String[] values = line.split(" "); - StashFinder.Chunk chunk = new StashFinder.Chunk(new ChunkPos(Integer.parseInt(values[0]), Integer.parseInt(values[1]))); - - chunk.chests = Integer.parseInt(values[2]); - chunk.shulkers = Integer.parseInt(values[3]); - chunk.enderChests = Integer.parseInt(values[4]); - chunk.furnaces = Integer.parseInt(values[5]); - chunk.dispensersDroppers = Integer.parseInt(values[6]); - chunk.hoppers = Integer.parseInt(values[7]); - - chunks.add(chunk); - } - - reader.close(); - } catch (Exception ignored) { - if (chunks == null) chunks = new ArrayList<>(); - } - } - } - - @Override - public String getInfoString() { - return String.valueOf(chunks.size()); - } - - private static class ChunkScreen extends WindowScreen { - private final StashFinder.Chunk chunk; - - public ChunkScreen(GuiTheme theme, StashFinder.Chunk chunk) { - super(theme, "Chunk at " + chunk.x + ", " + chunk.z); - - this.chunk = chunk; - } - - @Override - public void initWidgets() { - WTable t = add(theme.table()).expandX().widget(); - - // Total - t.add(theme.label("Total:")); - t.add(theme.label(chunk.getTotal() + "")); - t.row(); - - t.add(theme.horizontalSeparator()).expandX(); - t.row(); - - // Separate - t.add(theme.label("Chests:")); - t.add(theme.label(chunk.chests + "")); - t.row(); - - t.add(theme.label("Barrels:")); - t.add(theme.label(chunk.barrels + "")); - t.row(); - - t.add(theme.label("Shulkers:")); - t.add(theme.label(chunk.shulkers + "")); - t.row(); - - t.add(theme.label("Ender Chests:")); - t.add(theme.label(chunk.enderChests + "")); - t.row(); - - t.add(theme.label("Furnaces:")); - t.add(theme.label(chunk.furnaces + "")); - t.row(); - - t.add(theme.label("Dispensers and droppers:")); - t.add(theme.label(chunk.dispensersDroppers + "")); - t.row(); - - t.add(theme.label("Hoppers:")); - t.add(theme.label(chunk.hoppers + "")); - } - } -} - diff --git a/src/main/java/xyz/omegaware/addon/modules/ChatFilterModule.java b/src/main/java/xyz/omegaware/addon/modules/ChatFilterModule.java deleted file mode 100644 index 111c362..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/ChatFilterModule.java +++ /dev/null @@ -1,235 +0,0 @@ -package xyz.omegaware.addon.modules; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import meteordevelopment.meteorclient.gui.GuiTheme; -import meteordevelopment.meteorclient.gui.widgets.WWidget; -import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList; -import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList; -import meteordevelopment.meteorclient.gui.widgets.pressable.WButton; -import meteordevelopment.meteorclient.settings.*; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import xyz.omegaware.addon.OmegawareAddons; -import meteordevelopment.meteorclient.events.game.ReceiveMessageEvent; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.orbit.EventHandler; -import xyz.omegaware.addon.utils.Logger; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.util.List; - -import static xyz.omegaware.addon.utils.ServerCheck.isNot6B6T; - -public class ChatFilterModule extends Module { - public ChatFilterModule() { - super(OmegawareAddons.CATEGORY, "6B6T-chat-filter", "This module filters chat messages based on selected criteria."); - } - - private final SettingGroup sgGeneral = this.settings.getDefaultGroup(); - private final SettingGroup sgIgnoredUsers = this.settings.createGroup("Ignored Users"); - private final SettingGroup sgMessageStartFlags = this.settings.createGroup("Message Start Flags"); - private final SettingGroup sgMessageContains = this.settings.createGroup("Message Contains"); - - private final Setting rankedOnly = sgGeneral.add(new BoolSetting.Builder() - .name("ranked-users-only") - .description("Only show messages from players with a rank.") - .defaultValue(false) - .build() - ); - - private final Setting filterServerMessages = sgGeneral.add(new BoolSetting.Builder() - .name("filter-server-messages") - .description("Filter out the server's messages from the chat.") - .defaultValue(true) - .build() - ); - - private final Setting toggleIgnoredUsers = sgIgnoredUsers.add(new BoolSetting.Builder() - .name("toggle-ignored-users") - .description("Toggle ignoring of users.") - .defaultValue(true) - .build() - ); - - private final Setting> ignoredUsers = sgIgnoredUsers.add(new StringListSetting.Builder() - .name("filtered-users-list") - .description("A list of users to filter.") - .defaultValue(List.of("user1", "user2", "user3")) - .visible(toggleIgnoredUsers::get) - .build() - ); - - private final Setting toggleMessageStartFlags = sgMessageStartFlags.add(new BoolSetting.Builder() - .name("toggle-message-start-flags") - .description("Toggle filtering of messages that start with a selected flag.") - .defaultValue(true) - .build() - ); - - private final Setting> messageStartFlags = sgMessageStartFlags.add(new StringListSetting.Builder() - .name("message-start-flags") - .description("A list of flags that will get a message filtered if they are at the start of a players message.") - .defaultValue(List.of("!", "$", "%", "#", ".", "?")) - .visible(toggleMessageStartFlags::get) - .build() - ); - - private final Setting toggleMessageContainsFlags = sgMessageContains.add(new BoolSetting.Builder() - .name("toggle-message-contains-flags") - .description("Toggle filtering of messages that contain a selected flag.") - .defaultValue(true) - .build() - ); - - private final Setting> messageContainsFlags = sgMessageContains.add(new StringListSetting.Builder() - .name("message-contains-flags") - .description("A list of flags that will get a message filtered if they are contained in a players message.") - .defaultValue(List.of("discord", ".gg", "https://", "aternos")) - .visible(toggleMessageContainsFlags::get) - .build() - ); - - private static Integer filteredCount = 0; - private boolean loaded = false; - - private void incrementFilteredCount() { - filteredCount++; - saveFilteredCount(); - } - - private void saveFilteredCount() { - File configFile = OmegawareAddons.GetConfigFile("chat-filter", "filtered.count"); - - try { - //noinspection ResultOfMethodCallIgnored - configFile.getParentFile().mkdirs(); - - Writer writer = new FileWriter(configFile); - JsonObject payload = new JsonObject(); - payload.addProperty("count", filteredCount); - writer.append(payload.toString()); - writer.close(); - } catch (Exception ignored) { - OmegawareAddons.LOG.info("Failed to save Filtered Message count to {}", configFile.toPath()); - } - } - - public void loadFilteredCount() { - if (loaded) return; - - File configFile = OmegawareAddons.GetConfigFile("chat-filter", "filtered.count"); - if (!configFile.exists()) { - OmegawareAddons.LOG.warn("{} not found!", configFile.toPath()); - return; - } - - try { - String content = Files.readString(configFile.toPath()); - JsonObject payload = JsonParser.parseString(content).getAsJsonObject(); - if (payload.has("count")) { - filteredCount = payload.get("count").getAsInt(); - loaded = true; - } - } catch (IOException e) { - OmegawareAddons.LOG.error("Failed to load Filtered Message count from {}: {}", configFile.toPath(), e.getMessage()); - } - } - - @Override - public void onActivate() { - if (isNot6B6T()) { - Logger.error("%s is only intended for use on 6b6t.", name.replace("-", " ")); - toggle(); - return; - } - - loadFilteredCount(); - } - - @EventHandler - private void onMessageReceive(ReceiveMessageEvent event) { - if (!isActive() || mc.player == null) return; - String message = event.getMessage().getString(); - - if ((message.startsWith("Welcome to 6b6t.org") || message.startsWith("You can vote! Type /vote") || message.startsWith("---------------------------")) && filterServerMessages.get()) { - event.cancel(); - incrementFilteredCount(); - return; - } - - if (!message.contains("»")) return; - - String username = message.split(" » ")[0]; - if (username.equals(mc.player.getNameForScoreboard())) return; - - boolean isRanked = false; - if (message.startsWith("[")) { - isRanked = true; - message = message.substring(message.indexOf("]") + 1).trim(); - } - - if (rankedOnly.get() && !isRanked) { - event.cancel(); - incrementFilteredCount(); - return; - } - - if (toggleIgnoredUsers.get() && !ignoredUsers.get().isEmpty() && ignoredUsers.get().contains(username)) { - event.cancel(); - incrementFilteredCount(); - return; - } - - message = message.substring(message.indexOf("»") + 1).trim(); - - if (toggleMessageStartFlags.get() && !messageStartFlags.get().isEmpty()) { - for (String flag : messageStartFlags.get()) { - if (message.startsWith(flag)) { - event.cancel(); - incrementFilteredCount(); - return; - } - } - } - - if (toggleMessageContainsFlags.get() && !messageContainsFlags.get().isEmpty()){ - for (String flag : messageContainsFlags.get()) { - if (message.contains(flag)) { - event.cancel(); - incrementFilteredCount(); - return; - } - } - } - - // Little thing for me as the Developer :) - if (username.equals("LostEmotions") || username.equals("LostFriendships")) { - Text msg = Text.literal("[").formatted(Formatting.WHITE) - .append(Text.literal("OmegaWare").formatted(Formatting.AQUA)) - .append(Text.literal("] ")) - .append(username).formatted(Formatting.AQUA) - .append(Text.literal(" » ").formatted(Formatting.WHITE)) - .append(Text.literal(message).formatted(Formatting.AQUA)); - event.setMessage(msg); - } - } - - @Override - public WWidget getWidget(GuiTheme theme) { - WVerticalList list = theme.verticalList(); - WHorizontalList hList = list.add(theme.horizontalList()).expandX().widget(); - - WButton btn = theme.button("Print number of filtered messages"); - btn.action = () -> { - Logger.info("%sTotal Filtered Messages: %s%d", Formatting.GREEN, Formatting.WHITE, filteredCount); - }; - hList.add(btn); - - return list; - } -} diff --git a/src/main/java/xyz/omegaware/addon/modules/ItemFrameDupeModule.java b/src/main/java/xyz/omegaware/addon/modules/ItemFrameDupeModule.java deleted file mode 100644 index 7343d1f..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/ItemFrameDupeModule.java +++ /dev/null @@ -1,344 +0,0 @@ -package xyz.omegaware.addon.modules; - -import meteordevelopment.meteorclient.events.world.TickEvent; -import meteordevelopment.meteorclient.settings.BoolSetting; -import meteordevelopment.meteorclient.settings.IntSetting; -import meteordevelopment.meteorclient.settings.Setting; -import meteordevelopment.meteorclient.settings.SettingGroup; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.meteorclient.utils.player.FindItemResult; -import meteordevelopment.meteorclient.utils.player.InvUtils; -import meteordevelopment.orbit.EventHandler; -import net.minecraft.entity.Entity; -import net.minecraft.entity.decoration.ItemFrameEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.GameMode; -import org.jetbrains.annotations.NotNull; -import xyz.omegaware.addon.OmegawareAddons; -import xyz.omegaware.addon.utils.Logger; - -import java.util.ArrayList; -import java.util.List; - -import static xyz.omegaware.addon.utils.ServerCheck.isNot6B6T; - -// Shamelessly taken from https://github.com/kybe236/rusher-auto-item-frame-dupe/ -public class ItemFrameDupeModule extends Module { - public ItemFrameDupeModule() { - super(OmegawareAddons.CATEGORY, "6B6T-item-frame-dupe", "automates the 6b6t item frame dupe"); - } - - private final SettingGroup sgGeneral = this.settings.getDefaultGroup(); - - private final Setting rotationCount = sgGeneral.add(new IntSetting.Builder() - .name("Rotation-Count") - .defaultValue(1) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting placeToInsertDelay = sgGeneral.add(new IntSetting.Builder() - .name("Place-to-Insert-Delay") - .defaultValue(0) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting insertToRotateDelay = sgGeneral.add(new IntSetting.Builder() - .name("Insert-to-Rotate-Delay") - .defaultValue(0) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting rotateToRotateDelay = sgGeneral.add(new IntSetting.Builder() - .name("Rotate-to-Rotate-Delay") - .defaultValue(0) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting rotateToBreakDelay = sgGeneral.add(new IntSetting.Builder() - .name("Rotate-to-Break-Delay") - .defaultValue(0) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting breakToPlaceDelay = sgGeneral.add(new IntSetting.Builder() - .name("Break-to-Place-Delay") - .defaultValue(0) - .min(0) - .sliderMax(10) - .build() - ); - - private final Setting dropShulkers = sgGeneral.add(new BoolSetting.Builder() - .name("drop-shulkers") - .defaultValue(true) - .build() - ); - - private final Setting maxShulkersOfTypeInInventory = sgGeneral.add(new IntSetting.Builder() - .name("max-shulkers-of-type-in-inventory") - .description("Maximum number of shulker boxes of the same type allowed in the inventory.") - .defaultValue(5) - .min(1) - .sliderMax(27) - .build() - ); - - private final Setting smartShulkerQueue = sgGeneral.add(new BoolSetting.Builder() - .name("smart-shulker-queue") - .description("Uses a queue to cycle through shulker boxes.") - .defaultValue(false) - .build() - ); - - public static ArrayList shulkerQueue = new ArrayList<>(); - int shulkerQueueIndex = 0; - int currentRotationCount = 0; - int forceDelay = 0; - - @Override - public void onActivate() { - if (isNot6B6T()) { - Logger.error("%s is only intended for use on 6b6t.", name.replace("-", " ")); - toggle(); - } - } - - @EventHandler - private void onTickPost(TickEvent.Post event) { - if (!isActive()) return; - - // if interacting with an item skip the tick - if (mc.player != null && (mc.player.isUsingItem())) return; - - if (forceDelay != 0) { - forceDelay--; - return; - } - - if (mc.player == null || mc.world == null || mc.interactionManager == null) return; - if (mc.world.getBlockState(mc.player.getBlockPos().up(3)).isAir()) return; - if (mc.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) return; - - Box blockAbovePlayer = new Box(mc.player.getBlockPos().up(2)); - List entitiesAbovePlayer = mc.world.getOtherEntities(null, blockAbovePlayer); - entitiesAbovePlayer.removeIf(entity -> !(entity instanceof ItemFrameEntity)); - - if (entitiesAbovePlayer.isEmpty()) { - if (!getItemFrame()) return; - placeItemFrame(); - forceDelay = placeToInsertDelay.get(); - return; - } - - if (dropShulkers.get()) { - if (smartShulkerQueue.get() && !shulkerQueue.isEmpty()) { - for (ItemStack queuedShulker : shulkerQueue) { - int count = 0; - List indices = new ArrayList<>(); - for (int i = 0; i < mc.player.getInventory().size(); i++) { - ItemStack invStack = mc.player.getInventory().getStack(i); - if (!invStack.isEmpty() && - invStack.toHoverableText().equals(queuedShulker.toHoverableText()) && - invStack.getItem() == queuedShulker.getItem() && - isShulkerBox(invStack.getItem())) { - count++; - indices.add(i); - } - } - - - // If count exceeds the maximum allowed, drop the extras. - if (count > maxShulkersOfTypeInInventory.get()) { - int dropCount = count - maxShulkersOfTypeInInventory.get(); - for (int index : indices) { - if (dropCount <= 0) break; - int containerIndex = (index < 9) ? index + 36 : index; - if (!isShulkerBox(mc.player.getInventory().getStack(containerIndex).getItem())) continue; - - InvUtils.drop().slot(containerIndex); - dropCount--; - } - } - } - } - } - - ItemFrameEntity frame = (ItemFrameEntity)entitiesAbovePlayer.getFirst(); - if (frame.getHeldItemStack().isEmpty()) { - if (!getShulker()) return; - interactItemFrame(frame); - forceDelay = insertToRotateDelay.get(); - } else if (currentRotationCount >= rotationCount.get()) { - attackItemFrame(frame); - forceDelay = breakToPlaceDelay.get(); - currentRotationCount = 0; - } else { - interactItemFrame(frame); - currentRotationCount++; - if (currentRotationCount >= rotationCount.get()) { - forceDelay = rotateToBreakDelay.get(); - } else { - forceDelay = rotateToRotateDelay.get(); - } - } - } - - private boolean getItemFrame() { - if (mc.player == null) return false; - - int selectedSlot = mc.player.getInventory().selectedSlot; - if (mc.player.getInventory().getStack(selectedSlot).getItem() == Items.ITEM_FRAME) return true; - - FindItemResult res = InvUtils.findInHotbar(Items.ITEM_FRAME); - FindItemResult resInv = InvUtils.find(Items.ITEM_FRAME); - if (res.count() <= 0 && resInv.count() <= 0) return false; - - if (res.count() > 0) { - mc.player.getInventory().setSelectedSlot(res.slot()); - return true; - } - - InvUtils.move().fromId(resInv.slot()).to(selectedSlot); - return true; - } - - public void placeItemFrame() { - if (mc.world == null || mc.player == null || mc.interactionManager == null) return; - - BlockPos targetPos = mc.player.getBlockPos().up(3); - - if (mc.world.getBlockState(targetPos).isAir()) return; - - Direction face = Direction.DOWN; - - Vec3d hitPos = Vec3d.ofCenter(targetPos); - BlockHitResult hit = new BlockHitResult(hitPos, face, targetPos, false); - - mc.interactionManager.interactBlock(mc.player, Hand.MAIN_HAND, hit); - mc.player.swingHand(Hand.MAIN_HAND); - } - - public void interactItemFrame(ItemFrameEntity frame) { - if (mc.player == null || mc.interactionManager == null) return; - - mc.interactionManager.interactEntity(mc.player, frame, Hand.MAIN_HAND); - mc.player.swingHand(Hand.MAIN_HAND); - } - - public void attackItemFrame(ItemFrameEntity frame) { - if (mc.player == null || mc.interactionManager == null) return; - - mc.interactionManager.attackEntity(mc.player, frame); - mc.player.swingHand(Hand.MAIN_HAND); - } - - private boolean getShulker() { - if (mc.player == null) return false; - - if (smartShulkerQueue.get()) { - if (shulkerQueue.isEmpty()) return false; - if (shulkerQueueIndex >= shulkerQueue.size()) { - shulkerQueueIndex = 0; - } - - ItemStack shulkerStack = shulkerQueue.get(shulkerQueueIndex); - shulkerQueueIndex++; - if (shulkerStack.isEmpty()) return false; - - FindItemResult hotbarRes = InvUtils.findInHotbar(itemStack -> { - Item item = itemStack.getItem(); - return isShulkerBox(item) && itemStack.getCount() > 0 && itemStack.isOf(shulkerStack.getItem()); - }); - - if (hotbarRes.count() > 0) { - ItemStack itemStack = mc.player.getInventory().getStack(hotbarRes.slot()); - if (itemStack.isEmpty()) return false; - - if (itemStack.toHoverableText().equals(shulkerStack.toHoverableText()) && itemStack.getItem() == shulkerStack.getItem()) { - mc.player.getInventory().setSelectedSlot(hotbarRes.slot()); - return true; - } - return false; - } - - FindItemResult invRes = InvUtils.find(itemStack -> { - Item item = itemStack.getItem(); - return isShulkerBox(item) && itemStack.getCount() > 0 && itemStack.isOf(shulkerStack.getItem()); - }); - - if (invRes.count() > 0) { - for (int i = 0; i < invRes.count(); i++) { - ItemStack itemStack = mc.player.getInventory().getStack(invRes.slot()); - if (itemStack.toHoverableText().equals(shulkerStack.toHoverableText()) && itemStack.getItem() == shulkerStack.getItem()) { - InvUtils.move().fromId(invRes.slot()).to(mc.player.getInventory().selectedSlot); - return true; - } - } - } - - return false; - } - - FindItemResult invRes = InvUtils.find(itemStack -> { - Item item = itemStack.getItem(); - return isShulkerBox(item) && itemStack.getCount() > 0; - }); - - FindItemResult hotbarRes = InvUtils.findInHotbar(itemStack -> { - Item item = itemStack.getItem(); - return isShulkerBox(item) && itemStack.getCount() > 0; - }); - - if (invRes.count() <= 0 && hotbarRes.count() <= 0) return false; - - if (hotbarRes.count() > 0) { - mc.player.getInventory().setSelectedSlot(hotbarRes.slot()); - return true; - } - - InvUtils.move().fromId(invRes.slot()).to(mc.player.getInventory().selectedSlot); - return true; - } - - private boolean isShulkerBox(Item item) { - List<@NotNull Item> SHULKERS = List.of( - Items.SHULKER_BOX, - Items.WHITE_SHULKER_BOX, - Items.ORANGE_SHULKER_BOX, - Items.MAGENTA_SHULKER_BOX, - Items.LIGHT_BLUE_SHULKER_BOX, - Items.YELLOW_SHULKER_BOX, - Items.LIME_SHULKER_BOX, - Items.PINK_SHULKER_BOX, - Items.GRAY_SHULKER_BOX, - Items.LIGHT_GRAY_SHULKER_BOX, - Items.CYAN_SHULKER_BOX, - Items.PURPLE_SHULKER_BOX, - Items.BLUE_SHULKER_BOX, - Items.BROWN_SHULKER_BOX, - Items.GREEN_SHULKER_BOX, - Items.RED_SHULKER_BOX, - Items.BLACK_SHULKER_BOX - ); - - return SHULKERS.contains(item); - } -} diff --git a/src/main/java/xyz/omegaware/addon/modules/TPAAutomationModule.java b/src/main/java/xyz/omegaware/addon/modules/TPAAutomationModule.java deleted file mode 100644 index f14b15e..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/TPAAutomationModule.java +++ /dev/null @@ -1,153 +0,0 @@ -package xyz.omegaware.addon.modules; - -import meteordevelopment.meteorclient.settings.*; -import meteordevelopment.meteorclient.systems.friends.Friends; -import meteordevelopment.meteorclient.utils.player.ChatUtils; -import net.minecraft.util.Formatting; -import xyz.omegaware.addon.OmegawareAddons; -import meteordevelopment.meteorclient.events.game.ReceiveMessageEvent; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.orbit.EventHandler; -import xyz.omegaware.addon.utils.Logger; - -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static xyz.omegaware.addon.utils.ServerCheck.isNot6B6T; - -public class TPAAutomationModule extends Module { - public TPAAutomationModule() { - super(OmegawareAddons.CATEGORY, "TPA-automations", "A module that automatically accepts or denies teleport requests based on a list of approved players."); - } - - private final SettingGroup sgApprovedUsers = this.settings.createGroup("Approved Users"); - private final SettingGroup sgGeneral = this.settings.createGroup("General"); - - private final Setting> approvedUsers = sgApprovedUsers.add(new StringListSetting.Builder() - .name("approved-users-list") - .description("A list of users to filter.") - .defaultValue(List.of("user1", "user2", "user3")) - .build() - ); - - private final Setting acceptFriends = sgGeneral.add(new BoolSetting.Builder() - .name("accept-friends") - .description("Automatically accept teleport requests from your Meteor friend list.") - .defaultValue(true) - .build() - ); - - private final Setting acceptTSRBots = sgGeneral.add(new BoolSetting.Builder() - .name("accept-tsr-bots") - .description("Automatically accept teleport requests that are from the TSR bot users.") - .defaultValue(true) - .build() - ); - - private final Setting autoDeny = sgGeneral.add(new BoolSetting.Builder() - .name("auto-deny") - .description("Automatically deny teleport requests that are not from approved users.") - .defaultValue(true) - .build() - ); - - private final Setting printTpaDetected = sgGeneral.add(new BoolSetting.Builder() - .name("print-tpa-detected") - .description("Print a message when a teleport request is detected.") - .defaultValue(true) - .build() - ); - - private final Setting printTpaAccepted = sgGeneral.add(new BoolSetting.Builder() - .name("print-tpa-accepted") - .description("Print a message when a teleport request is accepted.") - .defaultValue(true) - .build() - ); - - private final Setting printTpaIgnored = sgGeneral.add(new BoolSetting.Builder() - .name("print-tpa-ignored") - .description("Print a message when a teleport request is ignored.") - .defaultValue(true) - .build() - ); - - private final Setting filterTpaMessages = sgGeneral.add(new BoolSetting.Builder() - .name("filter-tpa-messages") - .description("Filter out the servers TPA messages from the chat.") - .defaultValue(true) - .build() - ); - - private static final Pattern TPA_MESSAGE_PATTERN = Pattern.compile("^Type /tpy ([A-Za-z0-9_]{3,16}) to accept or /tpn [A-Za-z0-9_]{3,16} to deny\\.$"); - private static final Pattern TPA_ACCEPTED_PATTERN = Pattern.compile("^Request from ([A-Za-z0-9_]{3,16}) accepted!$"); - private static final Pattern TPA_DENIED_PATTERN = Pattern.compile("^Request from ([A-Za-z0-9_]{3,16}) denied!$"); - private static final Pattern TPA_REQUEST_PATTERN = Pattern.compile("^([A-Za-z0-9_]{3,16}) wants to teleport to you\\.$"); - - private static final Set TSR_KIT_BOT_USERS = Set.of( - "royalburner", - "Poolyin", - "PoolyinHelper", - "RoyalHelper", - "TSRMANIA", - "WomenAreScary", - "ElectricCallboy" - ); - - @Override - public void onActivate() { - if (isNot6B6T()) { - Logger.error("%s is only intended for use on 6b6t.", name.replace("-", " ")); - toggle(); - } - } - - @EventHandler - private void onMessageReceive(ReceiveMessageEvent event) { - if (!isActive() || mc.player == null) return; - - String message = event.getMessage().getString(); - - if (filterTpaMessages.get()) { - Matcher matcher = TPA_MESSAGE_PATTERN.matcher(message); - if (matcher.matches()) { - event.cancel(); - return; - } - - matcher = TPA_ACCEPTED_PATTERN.matcher(message); - if (matcher.matches()) { - event.cancel(); - return; - } - - matcher = TPA_DENIED_PATTERN.matcher(message); - if (matcher.matches() && autoDeny.get()) { - event.cancel(); - return; - } - } - - Matcher matcher = TPA_REQUEST_PATTERN.matcher(message); - if (!matcher.matches()) return; - - String username = matcher.group(1); - - if (printTpaDetected.get()) Logger.info("%sTPA Detected:%s %s!", Formatting.RED, Formatting.WHITE, username); - - if (approvedUsers.get().contains(username) || (acceptFriends.get() && Friends.get().get(username) != null) || (acceptTSRBots.get() && TSR_KIT_BOT_USERS.contains(username))) { - ChatUtils.sendPlayerMsg("/tpy " + username); - - if (printTpaAccepted.get()) Logger.info("%sAuto Accepted:%s %s!", Formatting.GREEN, Formatting.WHITE, username); - - } else if (autoDeny.get()){ - ChatUtils.sendPlayerMsg("/tpn " + username); - - if (printTpaIgnored.get()) Logger.info("%sIgnored:%s %s!", Formatting.RED, Formatting.WHITE, username); - } - - if (filterTpaMessages.get() && printTpaDetected.get()) event.cancel(); - } -} diff --git a/src/main/java/xyz/omegaware/addon/modules/TSRKitBotModule.java b/src/main/java/xyz/omegaware/addon/modules/TSRKitBotModule.java deleted file mode 100644 index b65de65..0000000 --- a/src/main/java/xyz/omegaware/addon/modules/TSRKitBotModule.java +++ /dev/null @@ -1,745 +0,0 @@ -package xyz.omegaware.addon.modules; - -import com.google.gson.*; -import meteordevelopment.discordipc.DiscordIPC; -import meteordevelopment.meteorclient.gui.GuiTheme; -import meteordevelopment.meteorclient.gui.widgets.WLabel; -import meteordevelopment.meteorclient.gui.widgets.WWidget; -import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList; -import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList; -import meteordevelopment.meteorclient.gui.widgets.input.WTextBox; -import meteordevelopment.meteorclient.gui.widgets.pressable.WButton; -import meteordevelopment.meteorclient.settings.IntSetting; -import meteordevelopment.meteorclient.settings.Setting; -import meteordevelopment.meteorclient.settings.SettingGroup; -import meteordevelopment.meteorclient.systems.modules.Module; -import meteordevelopment.meteorclient.utils.network.Http; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.Formatting; -import xyz.omegaware.addon.OmegawareAddons; -import xyz.omegaware.addon.utils.Logger; - -import java.io.*; -import java.net.http.HttpResponse; -import java.nio.file.Files; - -import static xyz.omegaware.addon.utils.ServerCheck.isNot6B6T; - -public class TSRKitBotModule extends Module { - public TSRKitBotModule() { - super(OmegawareAddons.CATEGORY, "TSR-Clan-KitBot-API", "Make kit requests to the TSR Clan KitBot API."); - } - - private final SettingGroup sgKits = this.settings.createGroup("Kits", false); - - private static final String apiUrl = "https://req.tsr-clan.org"; - - private static String apiKey = null; - - private final Setting pvpKit = sgKits.add(new IntSetting.Builder() - .name("kit-pvp") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting cpvpKit = sgKits.add(new IntSetting.Builder() - .name("kit-cpvp") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting refillKit = sgKits.add(new IntSetting.Builder() - .name("kit-refill") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting griefKit = sgKits.add(new IntSetting.Builder() - .name("kit-grief") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting hunterKit = sgKits.add(new IntSetting.Builder() - .name("kit-hunter") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting mapartKit = sgKits.add(new IntSetting.Builder() - .name("kit-mapart") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting highwayKit = sgKits.add(new IntSetting.Builder() - .name("kit-highway") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting redstoneKit = sgKits.add(new IntSetting.Builder() - .name("kit-redstone") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting buildKit = sgKits.add(new IntSetting.Builder() - .name("kit-build") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting build2Kit = sgKits.add(new IntSetting.Builder() - .name("kit-build2") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting build3Kit = sgKits.add(new IntSetting.Builder() - .name("kit-build3") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting build4Kit = sgKits.add(new IntSetting.Builder() - .name("kit-build4") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting build5Kit = sgKits.add(new IntSetting.Builder() - .name("kit-build5") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting build6Kit = sgKits.add(new IntSetting.Builder() - .name("kit-build6") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting toolsKit = sgKits.add(new IntSetting.Builder() - .name("kit-tools") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting totemKit = sgKits.add(new IntSetting.Builder() - .name("kit-totem") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - private final Setting censoredKit = sgKits.add(new IntSetting.Builder() - .name("kit-censored") - .description("Number of this kit you want to order.") - .defaultValue(0) - .min(0) - .sliderMax(27) - .build() - ); - - public static boolean getIsLinked(String... code) { - if (apiKey != null && !apiKey.isEmpty()) return true; - - if (DiscordIPC.getUser() == null) { - Logger.error("You must have the Discord Presence module enabled"); - return false; - } - - JsonObject payload = new JsonObject(); - assert MinecraftClient.getInstance().player != null; - payload.addProperty("minecraft_username", MinecraftClient.getInstance().player.getName().getString()); - payload.addProperty("discord_id", DiscordIPC.getUser().id); - payload.addProperty("retrieve_code", code.length > 0 ? code[0] : ""); - - Http.Request request = Http.post(apiUrl + "/meteor/link") - .header("Content-Type", "application/json") - .bodyJson(payload.toString()); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - if (response.statusCode() == 200) { - String message = response.body().get("message").getAsString(); - if (message != null && message.equals("Retrieval code sent to your Discord DMs.")) { - Logger.info("%sMessage: %s%sGrab the code and use the command .auth ", Formatting.GREEN, Formatting.WHITE, message); - return false; - } - - // print api key to chat - if (response.body().has("api_key")) { - apiKey = response.body().get("api_key").getAsString(); - Logger.info("%sSet API Key:%s %s", Formatting.GREEN, Formatting.WHITE, apiKey); - - saveApiKey(apiKey); - } else { - Logger.error("API Key not found."); - } - - return apiKey != null && !apiKey.isEmpty(); - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return false; - } - - Logger.error("%s", response.body().get("error").getAsString()); - return false; - } - } - - private static void conditionallyPrintOrders(String... statusFlag) { - if (!getIsLinked()) return; - - assert MinecraftClient.getInstance().player != null; - Http.Request request = Http.get(apiUrl + "/order/history?minecraft_username=" + MinecraftClient.getInstance().player.getName().getString()) - .header("Content-Type", "application/json") - .header("x-api-key", apiKey); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - JsonArray orders = response.body().getAsJsonArray("orders"); - if (orders.isEmpty()) { - Logger.info("%sNo order history.", Formatting.GREEN); - return; - } - - for (JsonElement order : orders) { - JsonObject orderObj = order.getAsJsonObject(); - if (!orderObj.has("order_id") || !orderObj.has("status") || !orderObj.has("request_type") || !orderObj.has("quantity")) { - continue; // Skip if any required field is missing - } - - String orderId = orderObj.get("order_id").isJsonNull() ? "null" : orderObj.get("order_id").getAsString(); - String status = orderObj.get("status").isJsonNull() ? "null" : orderObj.get("status").getAsString(); - String requestType = orderObj.get("request_type").isJsonNull() ? "null" : orderObj.get("request_type").getAsString(); - String quantity = orderObj.get("quantity").isJsonNull() ? "null" : orderObj.get("quantity").getAsString(); - - boolean isValidStatus = false; - for (String flag : statusFlag) { - if (status.equals(flag)) { - isValidStatus = true; - break; - } - } - if (!isValidStatus) continue; - - Logger.info("%sOrder ID:%s %s\n | %sStatus:%s %s\n | %sRequest Type:%s %s\n | %sQuantity:%s %s", - Formatting.GREEN, Formatting.WHITE, orderId, Formatting.GREEN, Formatting.WHITE, status, - Formatting.GREEN, Formatting.WHITE, requestType, Formatting.GREEN, Formatting.WHITE, quantity); - } - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", response.body().get("error").getAsString()); - } - } - - private boolean loaded = false; - - @Override - public void onActivate() { - if (isNot6B6T()) { - Logger.error("%s is only intended for use on 6b6t.", name.replace("-", " ")); - toggle(); - return; - } - - if (loaded) return; - apiKey = loadApiKey(); - loaded = true; - } - - @Override - public WWidget getWidget(GuiTheme theme) { - WVerticalList list = theme.verticalList(); - WHorizontalList hList = list.add(theme.horizontalList()).expandX().widget(); - - - WButton getBalanceButton = theme.button("Get Balance"); - getBalanceButton.action = () -> { - if (!getIsLinked()) return; - - assert mc.player != null; - Http.Request request = Http.get(apiUrl + "/user?minecraft_username=" + mc.player.getName().getString()) - .header("Content-Type", "application/json") - .header("x-api-key", apiKey); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - Logger.info("%sBalance:%s %s ",Formatting.GREEN, Formatting.WHITE, response.body().get("credits").getAsString()); - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", response.body().get("error").getAsString()); - } - }; - hList.add(getBalanceButton); - - WButton getQueuePositionButton = theme.button("Get Queue Position"); - getQueuePositionButton.action = () -> { - if (!getIsLinked()) return; - - assert mc.player != null; - Http.Request request = Http.get(apiUrl + "/order/position?minecraft_username=" + mc.player.getName().getString()) - .header("Content-Type", "application/json") - .header("x-api-key", apiKey); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - if (response.body().has("message")) { - Logger.info("%sMessage:%s %s", Formatting.WHITE, Formatting.GREEN, response.body().get("message").getAsString()); - } else { - Logger.info("%sQueue Position:%s %s", Formatting.GREEN, Formatting.WHITE, response.body().get("position").getAsString()); - } - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", response.body().get("error").getAsString()); - } - }; - hList.add(getQueuePositionButton); - - list.add(theme.label("You can select a maximum of 27 kits if you have tokens or 1 if you don't.")); - - WHorizontalList hList2 = list.add(theme.horizontalList()).expandX().widget(); - - WButton orderButton = theme.button("Place Order"); - orderButton.action = () -> { - if (!getIsLinked()) return; - int kitTotal = pvpKit.get() + cpvpKit.get() + refillKit.get() + griefKit.get() + hunterKit.get() + mapartKit.get() + highwayKit.get() + redstoneKit.get() + buildKit.get() + build2Kit.get() + build3Kit.get() + build4Kit.get() + build5Kit.get() + build6Kit.get() + toolsKit.get() + totemKit.get() + censoredKit.get(); - if (kitTotal > 27) { - Logger.error("You can only order a maximum of 27 kits."); - return; - } - - if (kitTotal <= 0 ) { - Logger.error("You must select at least 1 kit."); - return; - } - - JsonObject payload = new JsonObject(); - assert mc.player != null; - payload.addProperty("minecraft_username", mc.player.getName().getString()); - payload.addProperty("request_type", kitTotal > 1 ? "credits" : "normal"); - - JsonArray kitOrders = new JsonArray(); - if (pvpKit.get() > 0) { - JsonObject pvpOrder = new JsonObject(); - pvpOrder.addProperty("kit", "pvp"); - pvpOrder.addProperty("quantity", pvpKit.get()); - - kitOrders.add(pvpOrder); - } - - if (cpvpKit.get() > 0) { - JsonObject cpvpOrder = new JsonObject(); - cpvpOrder.addProperty("kit", "cpvp"); - cpvpOrder.addProperty("quantity", cpvpKit.get()); - - kitOrders.add(cpvpOrder); - } - - if (refillKit.get() > 0) { - JsonObject refillOrder = new JsonObject(); - refillOrder.addProperty("kit", "refill"); - refillOrder.addProperty("quantity", refillKit.get()); - - kitOrders.add(refillOrder); - } - - if (griefKit.get() > 0) { - JsonObject griefOrder = new JsonObject(); - griefOrder.addProperty("kit", "grief"); - griefOrder.addProperty("quantity", griefKit.get()); - - kitOrders.add(griefOrder); - } - - if (hunterKit.get() > 0) { - JsonObject hunterOrder = new JsonObject(); - hunterOrder.addProperty("kit", "hunter"); - hunterOrder.addProperty("quantity", hunterKit.get()); - - kitOrders.add(hunterOrder); - } - - if (mapartKit.get() > 0) { - JsonObject mapartOrder = new JsonObject(); - mapartOrder.addProperty("kit", "mapart"); - mapartOrder.addProperty("quantity", mapartKit.get()); - - kitOrders.add(mapartOrder); - } - - if (highwayKit.get() > 0) { - JsonObject highwayOrder = new JsonObject(); - highwayOrder.addProperty("kit", "highway"); - highwayOrder.addProperty("quantity", highwayKit.get()); - - kitOrders.add(highwayOrder); - } - - if (redstoneKit.get() > 0) { - JsonObject redstoneOrder = new JsonObject(); - redstoneOrder.addProperty("kit", "redstone"); - redstoneOrder.addProperty("quantity", redstoneKit.get()); - - kitOrders.add(redstoneOrder); - } - - if (buildKit.get() > 0) { - JsonObject buildOrder = new JsonObject(); - buildOrder.addProperty("kit", "build"); - buildOrder.addProperty("quantity", buildKit.get()); - - kitOrders.add(buildOrder); - } - - if (build2Kit.get() > 0) { - JsonObject build2Order = new JsonObject(); - build2Order.addProperty("kit", "build2"); - build2Order.addProperty("quantity", build2Kit.get()); - - kitOrders.add(build2Order); - } - - if (build3Kit.get() > 0) { - JsonObject build3Order = new JsonObject(); - build3Order.addProperty("kit", "build3"); - build3Order.addProperty("quantity", build3Kit.get()); - - kitOrders.add(build3Order); - } - - if (build4Kit.get() > 0) { - JsonObject build4Order = new JsonObject(); - build4Order.addProperty("kit", "build4"); - build4Order.addProperty("quantity", build4Kit.get()); - - kitOrders.add(build4Order); - } - - if (build5Kit.get() > 0) { - JsonObject build5Order = new JsonObject(); - build5Order.addProperty("kit", "build5"); - build5Order.addProperty("quantity", build5Kit.get()); - - kitOrders.add(build5Order); - } - - if (build6Kit.get() > 0) { - JsonObject build6Order = new JsonObject(); - build6Order.addProperty("kit", "build6"); - build6Order.addProperty("quantity", build6Kit.get()); - - kitOrders.add(build6Order); - } - - if (toolsKit.get() > 0) { - JsonObject toolsOrder = new JsonObject(); - toolsOrder.addProperty("kit", "tools"); - toolsOrder.addProperty("quantity", toolsKit.get()); - - kitOrders.add(toolsOrder); - } - - if (totemKit.get() > 0) { - JsonObject totemOrder = new JsonObject(); - totemOrder.addProperty("kit", "totem"); - totemOrder.addProperty("quantity", totemKit.get()); - - kitOrders.add(totemOrder); - } - - if (censoredKit.get() > 0) { - JsonObject censoredOrder = new JsonObject(); - censoredOrder.addProperty("kit", "censored"); - censoredOrder.addProperty("quantity", censoredKit.get()); - - kitOrders.add(censoredOrder); - } - - payload.add("kit_orders", kitOrders); - - Http.Request request = Http.post(apiUrl + "/order") - .header("Content-Type", "application/json") - .header("x-api-key", apiKey) - .bodyJson(payload.toString()); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - if (response.statusCode() == 200) { - if (response.body().has("message")) { - Logger.info("%sMessage:%s %s", Formatting.GREEN, Formatting.WHITE,response.body().get("message").getAsString()); - return; - } else if (response.body().has("error")) { - Logger.error("%s", response.body().get("error").getAsString()); - return; - } - - Logger.info("%sOrder Placed:%s %s | %sPriority:%s %s", Formatting.GREEN, Formatting.WHITE, response.body().get("order_id").getAsString(), Formatting.GREEN, Formatting.WHITE, response.body().get("priority").getAsString()); - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", Formatting.WHITE, response.body().get("error").getAsString()); - } - }; - hList2.add(orderButton); - - WButton listActiveOrdersButton = theme.button("List Active Orders"); - listActiveOrdersButton.action = () -> conditionallyPrintOrders("pending"); - hList2.add(listActiveOrdersButton); - - WButton listCompletedOrdersButton = theme.button("List Completed Orders"); - listCompletedOrdersButton.action = () -> conditionallyPrintOrders("completed"); - hList2.add(listCompletedOrdersButton); - - WButton listFailedOrdersButton = theme.button("List Failed Orders"); - listFailedOrdersButton.action = () -> conditionallyPrintOrders("failed"); - hList2.add(listFailedOrdersButton); - - WHorizontalList hList3 = list.add(theme.horizontalList()).expandX().widget(); - - WButton cancelAllButton = theme.button("Cancel All Orders"); - cancelAllButton.action = () -> { - if (!getIsLinked()) return; - - JsonObject payload = new JsonObject(); - assert mc.player != null; - payload.addProperty("minecraft_username", mc.player.getName().getString()); - - Http.Request request = Http.post(apiUrl + "/order/cancel") - .header("Content-Type", "application/json") - .header("x-api-key", apiKey) - .bodyJson(payload.toString()); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - Logger.info("%sCancel All Orders:%s %s", Formatting.GREEN, Formatting.WHITE, response.body().get("message").getAsString()); - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", Formatting.WHITE, response.body().get("error").getAsString()); - } - }; - hList3.add(cancelAllButton); - - WLabel label = theme.label("Order ID: "); - WTextBox textBox = theme.textBox(""); - textBox.minWidth = 100; - - WButton cancelButton = theme.button("Cancel Order"); - cancelButton.action = () -> { - if (!getIsLinked()) return; - - if (textBox.get().isEmpty()) { - Logger.error("Please enter an order ID."); - return; - } - - if (!textBox.get().matches("\\d+")) { - Logger.error("Order ID must be a number."); - return; - } - - JsonObject payload = new JsonObject(); - payload.addProperty("order_id", textBox.get()); - - Http.Request request = Http.post(apiUrl + "/order/cancel") - .header("Content-Type", "application/json") - .header("x-api-key", apiKey) - .bodyJson(payload.toString()); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - Logger.info("%sOrder Cancelled:%s %s", Formatting.GREEN, Formatting.WHITE, response.body().get("order_id").getAsString()); - } else { - if (response.body() == null) { - Logger.error("No response from server"); - return; - } - - Logger.error("%s", response.body().get("error").getAsString()); - } - }; - hList3.add(cancelButton); - hList3.add(label); - hList3.add(textBox); - - WHorizontalList hList4 = list.add(theme.horizontalList()).expandX().widget(); - - WLabel amountLabel = theme.label("Amount: "); - WTextBox amountTextBox = theme.textBox(""); - amountTextBox.minWidth = 100; - - WLabel targetLabel = theme.label("Target MC Username or Discord ID: "); - WTextBox targetTextBox = theme.textBox(""); - targetTextBox.minWidth = 100; - - WButton sendTokensButton = theme.button("Send Tokens"); - sendTokensButton.action = () -> { - if (!getIsLinked()) return; - - if (amountTextBox.get().isEmpty() || targetTextBox.get().isEmpty()) { - Logger.error("Please enter an amount and a target Discord ID."); - return; - } - - if (!amountTextBox.get().matches("\\d+")) { - Logger.error("Amount must be a number."); - return; - } - - if (Integer.parseInt(amountTextBox.get()) <= 0) { - Logger.error("Amount must be at least 1"); - return; - } - - JsonObject payload = new JsonObject(); - assert mc.player != null; - payload.addProperty("from_minecraft_username", mc.player.getName().getString()); - payload.addProperty("to_discord_id", targetTextBox.get()); - payload.addProperty("amount", Integer.parseInt(amountTextBox.get())); - - Http.Request request = Http.post(apiUrl + "/transfer") - .header("Content-Type", "application/json") - .header("x-api-key", apiKey) - .bodyJson(payload.toString()); - - HttpResponse response = request.sendJsonResponse(JsonObject.class); - - if (response.statusCode() == 200) { - if (response.body().has("error")) { - Logger.error("%s", response.body().get("error").getAsString()); - return; - } - - Logger.info("%sTokens Sent:%s %s | %sNew Balance:%s %s", - Formatting.GREEN, Formatting.WHITE, response.body().get("message").getAsString(), - Formatting.GREEN, Formatting.WHITE, response.body().get("from_balance").getAsString()); - } else { - if (response.body() == null) { - Logger.error("No response from server."); - return; - } - - Logger.error("%s", response.body().get("error").getAsString()); - } - }; - hList4.add(sendTokensButton); - hList4.add(amountLabel); - hList4.add(amountTextBox); - hList4.add(targetLabel); - hList4.add(targetTextBox); - - return list; - } - - private static void saveApiKey(String key) { - File configFile = OmegawareAddons.GetConfigFile("tsr-kitbot-api", "kitbot.key"); - try { - //noinspection ResultOfMethodCallIgnored - configFile.getParentFile().mkdirs(); - - Writer writer = new FileWriter(configFile); - JsonObject payload = new JsonObject(); - payload.addProperty("api_key", key); - payload.addProperty("last_updated", System.currentTimeMillis()); - writer.append(payload.toString()); - writer.close(); - } catch (Exception ignored) { - OmegawareAddons.LOG.error("Failed to save API Key to {}", configFile.toPath()); - } - } - - private String loadApiKey() { - File configFile = OmegawareAddons.GetConfigFile("tsr-kitbot-api", "kitbot.key"); - if (!configFile.exists()) { - OmegawareAddons.LOG.warn("{} not found!", configFile.toPath()); - return null; - } - - try { - String content = Files.readString(configFile.toPath()); - JsonObject payload = JsonParser.parseString(content).getAsJsonObject(); - if (payload.has("api_key")) { - return payload.get("api_key").getAsString(); - } else { - OmegawareAddons.LOG.warn("No API key found!"); - return null; - } - } catch (IOException e) { - OmegawareAddons.LOG.error("Failed to load API key: {}", e.getMessage()); - return null; - } - } -}