Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -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
}
49 changes: 0 additions & 49 deletions build.gradle.kts

This file was deleted.

Binary file removed deploy.jar
Binary file not shown.
17 changes: 12 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repo files of interest:\n'
git ls-files 'gradle.properties' 'build.gradle' 'build.gradle.kts' 'settings.gradle' 'settings.gradle.kts' | sed 's#^`#-` #'

printf '\nRelevant property references:\n'
rg -n 'loom_version|fabric-loom|fabricmc|minecraft_version|loader_version|fabric_api_version' gradle.properties build.gradle build.gradle.kts settings.gradle settings.gradle.kts || true

printf '\nCurrent gradle.properties contents:\n'
cat -n gradle.properties

Repository: Sk1erLLC/AutoGG

Length of output: 1461


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import urllib.request, ssl
url = 'https://maven.fabricmc.net/net/fabricmc/fabric-loom/maven-metadata.xml'
try:
    with urllib.request.urlopen(url, timeout=20, context=ssl.create_default_context()) as r:
        data = r.read().decode('utf-8', 'replace')
    print(data[:4000])
except Exception as e:
    print('ERROR:', e)
PY

Repository: Sk1erLLC/AutoGG

Length of output: 294


🌐 Web query:

Fabric Loom 1.17-SNAPSHOT 1.17.9 maven metadata fabricmc.net

💡 Result:

The Fabric Loom 1.17-SNAPSHOT maven metadata is located at the official Fabric Maven repository [1]. You can access the directory listing directly at https://maven.fabricmc.net/net/fabricmc/fabric-loom/1.17-SNAPSHOT/ [1]. The maven-metadata.xml file for this snapshot version serves as the central descriptor for the 1.17-SNAPSHOT builds, tracking the latest versions and build timestamps [1]. Additionally, the corresponding plugin marker metadata is available at https://maven.fabricmc.net/fabric-loom/fabric-loom.gradle.plugin/1.17-SNAPSHOT/ [2]. As of June 2026, Fabric Loom utilizes a versioning scheme where snapshot versions (e.g., 1.17-SNAPSHOT) are generated to allow users to pull the latest development builds [3]. Official stable releases for Fabric Loom are also published as distinct versions (e.g., 1.17.0-alpha.17, 1.17.9, etc.) and can be found under the same maven group ID (net.fabricmc) [4][5][6]. For development projects, ensure your build configuration is set to include the Fabric Maven repository [7].

Citations:


Pin Loom to a released version

1.17-SNAPSHOT pulls mutable snapshot artifacts, so the same commit can resolve different plugin bits over time and make builds non-reproducible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gradle.properties` at line 8, The Loom dependency is currently set to a
mutable snapshot, so update loom_version in gradle.properties from the SNAPSHOT
value to a specific released version. Use the existing loom_version property as
the single place to pin the plugin to an immutable release so builds remain
reproducible.

fabric_api_version=0.153.0+26.2

# Mod
mod_version=4.2.0
maven_group=club.sk1er
4 changes: 3 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
12 changes: 0 additions & 12 deletions root.gradle.kts

This file was deleted.

12 changes: 12 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
mavenCentral()
gradlePluginPortal()
}
}

rootProject.name = 'autogg'
27 changes: 0 additions & 27 deletions settings.gradle.kts

This file was deleted.

94 changes: 32 additions & 62 deletions src/main/java/club/sk1er/mods/autogg/AutoGG.java
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

package club.sk1er.mods.autogg;

import club.sk1er.mods.autogg.command.AutoGGCommand;
Expand All @@ -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<String> 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);
Comment on lines +50 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Don’t treat “triggers still loading” as an empty trigger set.

The JOIN handler runs detection once against AutoGG.INSTANCE.getTriggers().getServers(). Because trigger loading is async and getTriggers() returns an empty schema while unset, a player who joins before retrieval completes won’t be detected until reconnect/another detection path exists. Keep a distinct “not loaded” state and trigger server detection after RetrieveTriggersTask populates triggers.

Also applies to: 68-69

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/club/sk1er/mods/autogg/AutoGG.java` around lines 50 - 51, The
JOIN detection path in AutoGG is treating an unloaded trigger set as if it were
empty, so update AutoGG.getTriggers()/the JOIN handler to preserve a distinct
“not loaded” state instead of returning an empty schema. After
RetrieveTriggersTask completes and populates triggers, explicitly run or re-run
the server detection flow so players who joined before async loading finishes
are still detected without needing to reconnect.

}

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;
}
Expand Down
60 changes: 31 additions & 29 deletions src/main/java/club/sk1er/mods/autogg/command/AutoGGCommand.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading