diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..3ae61f0 --- /dev/null +++ b/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'net.fabricmc.fabric-loom' version "${loom_version}" +} + +version = project.mod_version +group = project.maven_group + +base { + archivesName = 'autogg' +} + +repositories { +} + +dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + // No mappings line — MC 26.x ships unobfuscated + implementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" +} + +processResources { + inputs.property "version", project.version + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 25 + it.options.encoding = 'UTF-8' +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 +} diff --git a/build.gradle.kts b/build.gradle.kts deleted file mode 100644 index 7513919..0000000 --- a/build.gradle.kts +++ /dev/null @@ -1,49 +0,0 @@ -import gg.essential.gradle.util.noServerRunConfigs - -plugins { - kotlin("jvm") - id("gg.essential.multi-version") - id("gg.essential.defaults") -} - -val modGroup: String by project -val modBaseName: String by project -group = modGroup -base.archivesName.set("$modBaseName-${platform.mcVersionStr}") - -repositories { - maven("https://repo.spongepowered.org/repository/maven-public/") - maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") -} - -loom { - noServerRunConfigs() - runConfigs { - getByName("client") { - programArgs("--tweakClass", "org.spongepowered.asm.launch.MixinTweaker") - } - } -} - -val embed by configurations.creating -configurations.implementation.get().extendsFrom(embed) - -dependencies { - embed("org.spongepowered:mixin:0.7-SNAPSHOT") - embed("gg.essential:vigilance:306") - embed(modImplementation("gg.essential:universalcraft-1.8.9-forge:369")!!) - modRuntimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.2.1") -} - -tasks.jar { - from(embed.files.map { zipTree(it) }) - - manifest.attributes( - mapOf( - "ModSide" to "CLIENT", - "FMLCorePluginContainsFMLMod" to "Yes, yes it does", - "TweakClass" to "org.spongepowered.asm.launch.MixinTweaker", - "TweakOrder" to "0" - ) - ) -} \ No newline at end of file diff --git a/deploy.jar b/deploy.jar deleted file mode 100644 index 758228f..0000000 Binary files a/deploy.jar and /dev/null differ diff --git a/gradle.properties b/gradle.properties index d92949a..4f17003 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,13 @@ -essential.defaults.loom=0 -loom.platform=forge -modGroup=club.sk1er -modBaseName=AutoGG - org.gradle.jvmargs=-Xmx2G +org.gradle.parallel=true +org.gradle.configuration-cache=false + +# Fabric — check https://fabricmc.net/develop for updates +minecraft_version=26.2 +loader_version=0.19.3 +loom_version=1.17-SNAPSHOT +fabric_api_version=0.153.0+26.2 + +# Mod +mod_version=4.2.0 +maven_group=club.sk1er diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17655d0..5dd3c01 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/root.gradle.kts b/root.gradle.kts deleted file mode 100644 index bb0ed09..0000000 --- a/root.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -import gg.essential.gradle.util.versionFromBuildIdAndBranch - -plugins { - kotlin("jvm") version "1.9.0" apply false - id("gg.essential.multi-version.root") -} - -version = versionFromBuildIdAndBranch() - -preprocess { - "1.8.9"(10809, "srg") -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e298b43 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = 'autogg' diff --git a/settings.gradle.kts b/settings.gradle.kts deleted file mode 100644 index ad92d72..0000000 --- a/settings.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - mavenCentral() - maven("https://maven.fabricmc.net") - maven("https://maven.architectury.dev/") - maven("https://maven.minecraftforge.net") - maven("https://repo.essential.gg/repository/maven-public") - } - plugins { - val egtVersion = "0.6.0" - id("gg.essential.multi-version.root") version egtVersion - } -} - -rootProject.buildFileName = "root.gradle.kts" - -listOf( - "1.8.9" -).forEach { version -> - include(":$version") - project(":$version").apply { - projectDir = file("versions/$version") - buildFileName = "../../build.gradle.kts" - } - -} \ No newline at end of file diff --git a/src/main/java/club/sk1er/mods/autogg/AutoGG.java b/src/main/java/club/sk1er/mods/autogg/AutoGG.java index 4579cfc..b5cfa44 100644 --- a/src/main/java/club/sk1er/mods/autogg/AutoGG.java +++ b/src/main/java/club/sk1er/mods/autogg/AutoGG.java @@ -1,21 +1,3 @@ -/* - * AutoGG - Automatically say a selectable phrase at the end of a game on supported servers. - * Copyright (C) 2020 Sk1er LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package club.sk1er.mods.autogg; import club.sk1er.mods.autogg.command.AutoGGCommand; @@ -24,85 +6,73 @@ import club.sk1er.mods.autogg.handlers.patterns.PlaceholderAPI; import club.sk1er.mods.autogg.handlers.web.WebHandler; import club.sk1er.mods.autogg.tasks.RetrieveTriggersTask; +import club.sk1er.mods.autogg.tasks.data.Server; import club.sk1er.mods.autogg.tasks.data.TriggersSchema; import club.sk1er.mods.autogg.util.JsonUtil; import com.google.gson.JsonObject; +import net.fabricmc.api.ClientModInitializer; import net.minecraft.client.Minecraft; -import net.minecraftforge.client.ClientCommandHandler; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -/** - * Contains the main class for AutoGG which handles trigger schema setting/getting and the main initialization code. - * - * @author ChachyDev - */ -@Mod(modid = "autogg", name = "AutoGG", version = "4.1.3") -public class AutoGG { - - @Mod.Instance +public class AutoGG implements ClientModInitializer { + public static final String MODID = "autogg"; + public static final Logger LOGGER = LoggerFactory.getLogger(MODID); public static AutoGG INSTANCE; private final String[] primaryGGStrings = {"gg", "GG", "gf", "Good Game", "Good Fight", "Good Round! :D"}; private final String[] secondaryGGStrings = {"Have a good day!", "<3", "AutoGG By Sk1er!", "gf", "Good Fight", "Good Round", ":D", "Well played!", "wp"}; - private TriggersSchema triggers; - private AutoGGConfig autoGGConfig; - - public boolean usingEnglish; + private volatile TriggersSchema triggers; + public volatile boolean usingEnglish = true; public static final ScheduledExecutorService POOL = Executors.newScheduledThreadPool(5); - @Mod.EventHandler - public void onFMLPreInitialization(FMLPreInitializationEvent event) { - POOL.submit(this::checkUserLanguage); - } + @Override + public void onInitializeClient() { + INSTANCE = this; - @Mod.EventHandler - public void onFMLInitialization(FMLInitializationEvent event) { - autoGGConfig = new AutoGGConfig(); - autoGGConfig.preload(); + AutoGGConfig.load(); Set joined = new HashSet<>(); joined.addAll(Arrays.asList(primaryGGStrings)); joined.addAll(Arrays.asList(secondaryGGStrings)); - PlaceholderAPI.INSTANCE.registerPlaceHolder("antigg_strings", String.join("|", joined)); - POOL.submit(new RetrieveTriggersTask()); - MinecraftForge.EVENT_BUS.register(new AutoGGHandler()); - ClientCommandHandler.instance.registerCommand(new AutoGGCommand()); + new AutoGGHandler().register(); + AutoGGCommand.register(); - // fix settings that were moved to seconds instead of ms - // so users aren't waiting 5000 seconds to send GG - if (autoGGConfig.getAutoGGDelay() > 5) autoGGConfig.setAutoGGDelay(1); - if (autoGGConfig.getSecondaryDelay() > 5) autoGGConfig.setSecondaryDelay(1); + POOL.submit(new RetrieveTriggersTask()); + POOL.submit(this::checkUserLanguage); } private void checkUserLanguage() { - final String username = Minecraft.getMinecraft().getSession().getUsername(); - final JsonObject json = WebHandler.fetchJson("https://api.sk1er.club/language/" + username); - final String language = JsonUtil.getOrDefaultString(json,"language", "ENGLISH"); - this.usingEnglish = "ENGLISH".equals(language); + try { + Thread.sleep(5000); + Minecraft mc = Minecraft.getInstance(); + if (mc.getUser() == null) return; + final String username = mc.getUser().getName(); + final JsonObject json = WebHandler.fetchJson("https://api.sk1er.club/language/" + username); + final String language = JsonUtil.getOrDefaultString(json, "language", "ENGLISH"); + this.usingEnglish = "ENGLISH".equals(language); + } catch (Exception e) { + LOGGER.error("Failed to check user language", e); + } } public TriggersSchema getTriggers() { - return triggers; + return triggers != null ? triggers : new TriggersSchema(new Server[0]); } public void setTriggers(TriggersSchema triggers) { this.triggers = triggers; } - public AutoGGConfig getAutoGGConfig() { - return autoGGConfig; - } - public String[] getPrimaryGGStrings() { return primaryGGStrings; } diff --git a/src/main/java/club/sk1er/mods/autogg/command/AutoGGCommand.java b/src/main/java/club/sk1er/mods/autogg/command/AutoGGCommand.java index abf9827..922ceea 100644 --- a/src/main/java/club/sk1er/mods/autogg/command/AutoGGCommand.java +++ b/src/main/java/club/sk1er/mods/autogg/command/AutoGGCommand.java @@ -1,40 +1,42 @@ package club.sk1er.mods.autogg.command; import club.sk1er.mods.autogg.AutoGG; -import club.sk1er.mods.autogg.handlers.gg.AutoGGHandler; import club.sk1er.mods.autogg.tasks.RetrieveTriggersTask; -import gg.essential.universal.ChatColor; -import gg.essential.universal.wrappers.message.UTextComponent; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; -import static club.sk1er.mods.autogg.AutoGG.POOL; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.literal; -public class AutoGGCommand extends CommandBase { - - @Override - public String getCommandName() { - return "autogg"; - } - - @Override - public String getCommandUsage(ICommandSender sender) { - return "autogg"; +public class AutoGGCommand { + public static void register() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register( + literal("autogg") + .executes(ctx -> { + sendMessage(ctx.getSource(), + ChatFormatting.GOLD + "[AutoGG] " + ChatFormatting.GRAY + + "Edit §econfig/autogg.json §7to change settings. " + + "Use §e/autogg refresh §7to reload triggers."); + return 1; + }) + .then(literal("refresh") + .executes(ctx -> { + AutoGG.POOL.submit(new RetrieveTriggersTask()); + sendMessage(ctx.getSource(), + ChatFormatting.GOLD + "[AutoGG] " + ChatFormatting.GREEN + "Refreshed triggers!"); + return 1; + })) + ) + ); } - @Override - public void processCommand(ICommandSender sender, String[] args) throws CommandException { - if (args.length == 1 && args[0].equalsIgnoreCase("refresh")) { - POOL.submit(new RetrieveTriggersTask()); - (new UTextComponent(ChatColor.GREEN + "Refreshed triggers!")).chat(); - return; + private static void sendMessage(FabricClientCommandSource source, String text) { + Minecraft mc = Minecraft.getInstance(); + if (mc.player != null) { + mc.player.sendSystemMessage(Component.literal(text)); } - AutoGGHandler.displayScreen = AutoGG.INSTANCE.getAutoGGConfig().gui(); - } - - @Override - public int getRequiredPermissionLevel() { - return 0; } } diff --git a/src/main/java/club/sk1er/mods/autogg/config/AutoGGConfig.java b/src/main/java/club/sk1er/mods/autogg/config/AutoGGConfig.java index 8418393..e407a4a 100644 --- a/src/main/java/club/sk1er/mods/autogg/config/AutoGGConfig.java +++ b/src/main/java/club/sk1er/mods/autogg/config/AutoGGConfig.java @@ -1,126 +1,68 @@ package club.sk1er.mods.autogg.config; -import gg.essential.vigilance.Vigilant; -import gg.essential.vigilance.data.Property; -import gg.essential.vigilance.data.PropertyType; - -import java.io.File; - -@SuppressWarnings("FieldMayBeFinal") -public class AutoGGConfig extends Vigilant { - @Property( - type = PropertyType.SWITCH, name = "AutoGG", - description = "Entirely toggles AutoGG", - category = "General", subcategory = "General" - ) - private boolean autoGGEnabled = true; - - @Property( - type = PropertyType.SWITCH, name = "Casual AutoGG", - description = "Enable AutoGG for things that don't give Karma such as Skyblock Events.", - category = "General", subcategory = "General" - ) - private boolean casualAutoGGEnabled; - - @Property( - type = PropertyType.SWITCH, name = "Anti GG", - description = "Remove GG messages from chat.", - category = "General", subcategory = "Miscellaneous" - ) - private boolean antiGGEnabled; - - @Property( - type = PropertyType.SWITCH, name = "Anti Karma", - description = "Remove Karma messages from chat.", - category = "General", subcategory = "Miscellaneous" - ) - private boolean antiKarmaEnabled; - - @Property( - type = PropertyType.SLIDER, name = "Delay", - description = "Delay after the game ends to say the message.\n§eMeasured in seconds.", - category = "General", subcategory = "General", - max = 5 - ) +import club.sk1er.mods.autogg.AutoGG; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +public class AutoGGConfig { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("autogg.json"); + + private static AutoGGConfig instance = new AutoGGConfig(); + + // General + private boolean modEnabled = true; + private boolean casualAutoGGEnabled = false; private int autoGGDelay = 1; - - @Property( - type = PropertyType.SELECTOR, name = "Phrase", - description = "Choose what message is said on game completion.", - category = "General", subcategory = "General", - options = {"gg", "GG", "gf", "Good Game", "Good Fight", "Good Round! :D"} - ) private int autoGGPhrase = 0; - @Property( - type = PropertyType.SWITCH, name = "Second Message", - description = "Enable a secondary message to send after your first GG.", - category = "General", subcategory = "Secondary Message" - ) - private boolean secondaryEnabled; + // Misc + private boolean antiGGEnabled = false; + private boolean antiKarmaEnabled = false; - @Property( - type = PropertyType.SELECTOR, name = "Phrase", - description = "Send a secondary message sent after the first GG message.", - category = "General", subcategory = "Secondary Message", - options = {"Have a good day!", "<3", "AutoGG By Sk1er!", "gf", "Good Fight", "Good Round", ":D", "Well played!", "wp"} - ) + // Secondary + private boolean secondaryEnabled = false; private int autoGGPhrase2 = 0; - - @Property( - type = PropertyType.SLIDER, name = "Second Message Delay", - description = "Delay between the first & second end of game messages.\n§eMeasured in seconds.", - category = "General", subcategory = "Secondary Message", - max = 5 - ) private int secondaryDelay = 1; - public AutoGGConfig() { - super(new File("./config/autogg.toml")); - initialize(); - } - - public boolean isModEnabled() { - return autoGGEnabled; + public static AutoGGConfig get() { + return instance; } - public boolean isCasualAutoGGEnabled() { - return casualAutoGGEnabled; + public static void load() { + if (Files.exists(CONFIG_PATH)) { + try (Reader reader = Files.newBufferedReader(CONFIG_PATH)) { + AutoGGConfig loaded = GSON.fromJson(reader, AutoGGConfig.class); + if (loaded != null) instance = loaded; + } catch (IOException e) { + AutoGG.LOGGER.error("Failed to load AutoGG config", e); + } + } + save(); } - public boolean isAntiGGEnabled() { - return antiGGEnabled; + public static void save() { + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { + GSON.toJson(instance, writer); + } catch (IOException e) { + AutoGG.LOGGER.error("Failed to save AutoGG config", e); + } } - public boolean isAntiKarmaEnabled() { - return antiKarmaEnabled; - } - - public int getAutoGGDelay() { - return autoGGDelay; - } - - public int getAutoGGPhrase() { - return autoGGPhrase; - } - - public boolean isSecondaryEnabled() { - return secondaryEnabled; - } - - public int getAutoGGPhrase2() { - return autoGGPhrase2; - } - - public int getSecondaryDelay() { - return secondaryDelay; - } - - public void setAutoGGDelay(int autoGGDelay) { - this.autoGGDelay = autoGGDelay; - } - - public void setSecondaryDelay(int secondaryDelay) { - this.secondaryDelay = secondaryDelay; - } + public boolean isModEnabled() { return modEnabled; } + public boolean isCasualAutoGGEnabled() { return casualAutoGGEnabled; } + public int getAutoGGDelay() { return Math.max(0, Math.min(5, autoGGDelay)); } + public int getAutoGGPhrase() { return Math.max(0, Math.min(5, autoGGPhrase)); } + public boolean isAntiGGEnabled() { return antiGGEnabled; } + public boolean isAntiKarmaEnabled() { return antiKarmaEnabled; } + public boolean isSecondaryEnabled() { return secondaryEnabled; } + public int getAutoGGPhrase2() { return Math.max(0, Math.min(8, autoGGPhrase2)); } + public int getSecondaryDelay() { return Math.max(0, Math.min(5, secondaryDelay)); } } diff --git a/src/main/java/club/sk1er/mods/autogg/detectors/branding/ServerBrandingDetector.java b/src/main/java/club/sk1er/mods/autogg/detectors/branding/ServerBrandingDetector.java index b444ec2..9ad3f82 100644 --- a/src/main/java/club/sk1er/mods/autogg/detectors/branding/ServerBrandingDetector.java +++ b/src/main/java/club/sk1er/mods/autogg/detectors/branding/ServerBrandingDetector.java @@ -3,10 +3,16 @@ import club.sk1er.mods.autogg.detectors.IDetector; import club.sk1er.mods.autogg.handlers.patterns.PatternHandler; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; public class ServerBrandingDetector implements IDetector { @Override public boolean detect(String data) { - return Minecraft.getMinecraft().thePlayer != null && PatternHandler.INSTANCE.getOrRegisterPattern(data).matcher(Minecraft.getMinecraft().thePlayer.getClientBrand()).matches(); + Minecraft mc = Minecraft.getInstance(); + if (mc.player == null || mc.getConnection() == null) return false; + ClientCommonPacketListenerImpl connection = (ClientCommonPacketListenerImpl) mc.getConnection(); + String brand = connection.serverBrand(); + if (brand == null) return false; + return PatternHandler.INSTANCE.getOrRegisterPattern(data).matcher(brand).matches(); } } diff --git a/src/main/java/club/sk1er/mods/autogg/detectors/ip/ServerIPDetector.java b/src/main/java/club/sk1er/mods/autogg/detectors/ip/ServerIPDetector.java index 352be60..f3055f4 100644 --- a/src/main/java/club/sk1er/mods/autogg/detectors/ip/ServerIPDetector.java +++ b/src/main/java/club/sk1er/mods/autogg/detectors/ip/ServerIPDetector.java @@ -3,10 +3,15 @@ import club.sk1er.mods.autogg.detectors.IDetector; import club.sk1er.mods.autogg.handlers.patterns.PatternHandler; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; public class ServerIPDetector implements IDetector { @Override public boolean detect(String data) { - return Minecraft.getMinecraft().thePlayer != null && PatternHandler.INSTANCE.getOrRegisterPattern(data).matcher(Minecraft.getMinecraft().getCurrentServerData().serverIP).matches(); + Minecraft mc = Minecraft.getInstance(); + if (mc.player == null) return false; + ServerData serverData = mc.getCurrentServer(); + if (serverData == null) return false; + return PatternHandler.INSTANCE.getOrRegisterPattern(data).matcher(serverData.ip).matches(); } } diff --git a/src/main/java/club/sk1er/mods/autogg/handlers/gg/AutoGGHandler.java b/src/main/java/club/sk1er/mods/autogg/handlers/gg/AutoGGHandler.java index c6d40e2..f18f0fe 100644 --- a/src/main/java/club/sk1er/mods/autogg/handlers/gg/AutoGGHandler.java +++ b/src/main/java/club/sk1er/mods/autogg/handlers/gg/AutoGGHandler.java @@ -1,35 +1,29 @@ package club.sk1er.mods.autogg.handlers.gg; import club.sk1er.mods.autogg.AutoGG; +import club.sk1er.mods.autogg.config.AutoGGConfig; import club.sk1er.mods.autogg.handlers.patterns.PatternHandler; import club.sk1er.mods.autogg.tasks.data.Server; import club.sk1er.mods.autogg.tasks.data.Trigger; -import gg.essential.universal.wrappers.message.UMessage; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.util.EnumChatFormatting; -import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraft.network.chat.Component; import java.util.concurrent.TimeUnit; import static club.sk1er.mods.autogg.AutoGG.POOL; -/** - * Where the magic happens... - * We handle which server's triggers should be used - * and how to detect which server the player is currently - * on. - */ public class AutoGGHandler { private volatile Server server; private long lastGG = 0; - @SubscribeEvent - public void onEntityJoinWorld(EntityJoinWorldEvent event) { - if (event.entity == Minecraft.getMinecraft().thePlayer && AutoGG.INSTANCE.getAutoGGConfig().isModEnabled()) { + public void register() { + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + server = null; + if (!AutoGGConfig.get().isModEnabled()) return; + POOL.submit(() -> { for (Server s : AutoGG.INSTANCE.getTriggers().getServers()) { try { @@ -37,106 +31,106 @@ public void onEntityJoinWorld(EntityJoinWorldEvent event) { server = s; return; } - } catch (Throwable e) { - // Stop log spam + } catch (Throwable ignored) { } } - - // In case if it's not null and we couldn't find the triggers for the current server. - server = null; }); - if (!AutoGG.INSTANCE.usingEnglish) { - new UMessage("AutoGG").chat(); - new UMessage("We've detected your Hypixel language isn't set to English! AutoGG will not work on other languages.\n" + - "If this is a mistake, feel free to ignore it.").chat(); + + if (!AutoGG.INSTANCE.usingEnglish && client.player != null) { + client.player.sendSystemMessage(Component.literal( + ChatFormatting.GOLD + "[AutoGG] " + ChatFormatting.RED + + "We've detected your Hypixel language isn't set to English! " + + "AutoGG will not work on other languages." + )); } - } + }); + + ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> server = null); + + ClientReceiveMessageEvents.ALLOW_CHAT.register((message, signedMessage, sender, params, receptionTimestamp) -> + handleIncoming(message.getString()) + ); + + ClientReceiveMessageEvents.ALLOW_GAME.register((message, overlay) -> { + if (overlay) return true; + return handleIncoming(message.getString()); + }); } - @SubscribeEvent - public void onClientChatReceived(ClientChatReceivedEvent event) { - if (event.type == 2) return; - String stripped = EnumChatFormatting.getTextWithoutFormattingCodes(event.message.getUnformattedText()); + // Returns false to cancel the message, true to allow it + private boolean handleIncoming(String rawMessage) { + if (!AutoGGConfig.get().isModEnabled() || server == null) return true; - if (AutoGG.INSTANCE.getAutoGGConfig().isModEnabled() && server != null) { + String stripped = ChatFormatting.stripFormatting(rawMessage); + + for (Trigger trigger : server.getTriggers()) { + switch (trigger.getType()) { + case ANTI_GG: + if (AutoGGConfig.get().isAntiGGEnabled() && + PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { + return false; + } + break; + case ANTI_KARMA: + if (AutoGGConfig.get().isAntiKarmaEnabled() && + PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { + return false; + } + break; + default: + break; + } + } + + POOL.submit(() -> { for (Trigger trigger : server.getTriggers()) { switch (trigger.getType()) { - case ANTI_GG: - if (AutoGG.INSTANCE.getAutoGGConfig().isAntiGGEnabled()) { - if (PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { - event.setCanceled(true); - return; - } + case NORMAL: + if (PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { + invokeGG(); + return; } break; - case ANTI_KARMA: - if (AutoGG.INSTANCE.getAutoGGConfig().isAntiKarmaEnabled()) { - if (PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { - event.setCanceled(true); - return; - } + case CASUAL: + if (AutoGGConfig.get().isCasualAutoGGEnabled() && + PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { + invokeGG(); + return; } break; + default: + break; } } + }); - POOL.submit(() -> { - // Casual GG feature - for (Trigger trigger : server.getTriggers()) { - switch (trigger.getType()) { - case NORMAL: - if (PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { - invokeGG(); - return; - } - break; - - case CASUAL: - if (AutoGG.INSTANCE.getAutoGGConfig().isCasualAutoGGEnabled()) { - if (PatternHandler.INSTANCE.getOrRegisterPattern(trigger.getPattern()).matcher(stripped).matches()) { - invokeGG(); - return; - } - } - break; - } - } - }); - } + return true; } private void invokeGG() { - // Better safe than sorry - if (server != null) { - String prefix = server.getMessagePrefix(); - - if (System.currentTimeMillis() - lastGG < 10_000) return; - lastGG = System.currentTimeMillis(); - - String ggMessage = AutoGG.INSTANCE.getPrimaryGGStrings()[AutoGG.INSTANCE.getAutoGGConfig().getAutoGGPhrase()]; - int delay = AutoGG.INSTANCE.getAutoGGConfig().getAutoGGDelay(); - - POOL.schedule(() -> Minecraft.getMinecraft().thePlayer.sendChatMessage(prefix.isEmpty() ? ggMessage : prefix + " " + ggMessage), delay, TimeUnit.SECONDS); - - if (AutoGG.INSTANCE.getAutoGGConfig().isSecondaryEnabled()) { - String secondGGMessage = AutoGG.INSTANCE.getSecondaryGGStrings()[AutoGG.INSTANCE.getAutoGGConfig().getAutoGGPhrase2()]; - int secondaryDelay = AutoGG.INSTANCE.getAutoGGConfig().getSecondaryDelay() + AutoGG.INSTANCE.getAutoGGConfig().getAutoGGDelay(); - - POOL.schedule(() -> Minecraft.getMinecraft().thePlayer.sendChatMessage(prefix.isEmpty() ? ggMessage : prefix + " " + secondGGMessage), secondaryDelay, TimeUnit.SECONDS); - } + if (server == null) return; + if (System.currentTimeMillis() - lastGG < 10_000) return; + lastGG = System.currentTimeMillis(); + + String prefix = server.getMessagePrefix(); + String ggMessage = AutoGG.INSTANCE.getPrimaryGGStrings()[AutoGGConfig.get().getAutoGGPhrase()]; + int delay = AutoGGConfig.get().getAutoGGDelay(); + + String firstMsg = prefix.isEmpty() ? ggMessage : prefix + " " + ggMessage; + POOL.schedule(() -> sendChat(firstMsg), delay, TimeUnit.SECONDS); + + if (AutoGGConfig.get().isSecondaryEnabled()) { + String secondMsg = AutoGG.INSTANCE.getSecondaryGGStrings()[AutoGGConfig.get().getAutoGGPhrase2()]; + String secondFull = prefix.isEmpty() ? secondMsg : prefix + " " + secondMsg; + int secondaryDelay = delay + AutoGGConfig.get().getSecondaryDelay(); + POOL.schedule(() -> sendChat(secondFull), secondaryDelay, TimeUnit.SECONDS); } } - /** - * Gui Handling - */ - public static GuiScreen displayScreen = null; - - @SubscribeEvent - public void onTick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.END) return; - if (displayScreen == null) return; - Minecraft.getMinecraft().displayGuiScreen(displayScreen); - displayScreen = null; + private static void sendChat(String message) { + Minecraft mc = Minecraft.getInstance(); + if (mc.player != null && mc.getConnection() != null) { + mc.getConnection().sendChat(message); + } } } diff --git a/src/main/java/club/sk1er/mods/autogg/handlers/patterns/PatternHandler.java b/src/main/java/club/sk1er/mods/autogg/handlers/patterns/PatternHandler.java index de5800c..9bfca2b 100644 --- a/src/main/java/club/sk1er/mods/autogg/handlers/patterns/PatternHandler.java +++ b/src/main/java/club/sk1er/mods/autogg/handlers/patterns/PatternHandler.java @@ -1,30 +1,17 @@ package club.sk1er.mods.autogg.handlers.patterns; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.regex.Pattern; -/** - * Helper for compiling Regular Expressions on startup to prevent them being compiled on each chat message. - * - * @author ChachyDev - */ public class PatternHandler { public static PatternHandler INSTANCE = new PatternHandler(); private final Map patternCache = new HashMap<>(); public Pattern getOrRegisterPattern(String pattern) { - String processedPattern = PlaceholderAPI.INSTANCE.process(pattern); - - Pattern p = patternCache.get(processedPattern); - if (p == null) { - p = patternCache.put(processedPattern, Pattern.compile(processedPattern)); - } - - return p; + String processed = PlaceholderAPI.INSTANCE.process(pattern); + return patternCache.computeIfAbsent(processed, Pattern::compile); } public void clearPatterns() { diff --git a/src/main/java/club/sk1er/mods/autogg/handlers/web/WebHandler.java b/src/main/java/club/sk1er/mods/autogg/handlers/web/WebHandler.java index 0350a85..dce83d0 100644 --- a/src/main/java/club/sk1er/mods/autogg/handlers/web/WebHandler.java +++ b/src/main/java/club/sk1er/mods/autogg/handlers/web/WebHandler.java @@ -2,12 +2,13 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; -import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.net.URL; import java.net.URLConnection; +import java.nio.charset.StandardCharsets; public class WebHandler { private static final Gson gson = new Gson(); @@ -19,7 +20,7 @@ public static JsonObject fetchJson(String url) { public static String fetchString(String url) { try { - return fetchString(new URL(url)); + return fetchString(URI.create(url).toURL()); } catch (Exception e) { return "malformed url"; } @@ -29,9 +30,8 @@ public static String fetchString(URL url) { try { URLConnection connection = url.openConnection(); connection.setRequestProperty("User-Agent", "AutoGG"); - try (InputStream in = connection.getInputStream()) { - return IOUtils.toString(in, "UTF-8"); + return new String(in.readAllBytes(), StandardCharsets.UTF_8); } } catch (IOException ex) { ex.printStackTrace(); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..2de5781 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "id": "autogg", + "version": "${version}", + "name": "AutoGG", + "description": "AutoGG automatically says a selectable phrase after a game has ended on supported servers.", + "authors": ["2Pi", "Sk1er LLC", "SirNapkin1334"], + "license": "LGPL-3.0", + "environment": "client", + "entrypoints": { + "client": ["club.sk1er.mods.autogg.AutoGG"] + }, + "depends": { + "fabricloader": ">=0.19.0", + "fabric-api": "*", + "minecraft": "26.2" + } +} diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info deleted file mode 100644 index 39792eb..0000000 --- a/src/main/resources/mcmod.info +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "modid": "autogg", - "name": "AutoGG", - "description": "AutoGG automatically says a selectable phrase after a game has ended on supported servers.", - "version": "${version}", - "mcversion": "${mcVersionStr}", - "url": "https://sk1er.club/", - "updateUrl": "", - "authorList": [ - "2Pi", - "Sk1er LLC", - "SirNapkin1334" - ], - "credits": "Created by 2PI, maintained and updated by Sk1er LLC. Regex update created by SirNapkin1334.", - "logoFile": "", - "screenshots": [], - "dependencies": [] - } -]