From b68bbf4684b6da9fc8a18372d1a7408cb3bf934d Mon Sep 17 00:00:00 2001 From: galvincraft-bot Date: Sat, 24 Jan 2026 15:54:56 +0000 Subject: [PATCH 1/5] chore(ci): standardize workflow and Gradle for Java 25 --- .github/workflows/build.yml | 36 ++++++++++++++++++++---- build.gradle | 21 +++++--------- gradle.properties | 18 +++++------- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8fc3827..405c477 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,26 +4,52 @@ # against bad commits. name: build -on: [pull_request, push] + +on: + pull_request: + paths: &build_paths + - '.github/workflows/build.yml' + - 'build.gradle' + - 'gradle.properties' + - 'gradle/**' + - 'gradlew' + - 'gradlew.bat' + - 'settings.gradle' + - 'src/**' + + push: + branches: [main] + paths: *build_paths + +concurrency: + group: "java-build-${{ github.ref }}" + cancel-in-progress: true jobs: build: - runs-on: ubuntu-24.04 + strategy: + matrix: + # Use these Java versions + java: [ + 25, # Current Java LTS + ] + runs-on: ubuntu-latest steps: - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper - uses: gradle/actions/wrapper-validation@v4 - - name: setup jdk + uses: gradle/wrapper-validation-action@v2 + - name: setup jdk ${{ matrix.java }} uses: actions/setup-java@v4 with: - java-version: '21' + java-version: ${{ matrix.java }} distribution: 'microsoft' - name: make gradle wrapper executable run: chmod +x ./gradlew - name: build run: ./gradlew build - name: capture build artifacts + if: ${{ matrix.java == '25' }} # Only upload artefacts built from latest java uses: actions/upload-artifact@v4 with: name: Artifacts diff --git a/build.gradle b/build.gradle index b81a0e2..92cd4c7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version "${loom_version}" + id 'net.fabricmc.fabric-loom' version "${loom_version}" id 'maven-publish' } @@ -21,11 +21,11 @@ repositories { dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + // NOTE: Not all projects use Fabric API, but there's no telling that we won't need it later. + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" } @@ -38,17 +38,14 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 21 + it.options.release = 25 } java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } jar { @@ -68,11 +65,7 @@ publishing { } } - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. repositories { // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b695fa3..01fa9e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,21 +1,17 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G +# Done to increase the memory available to Gradle. +org.gradle.jvmargs=-Xmx2G org.gradle.parallel=true -# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349 -org.gradle.configuration-cache=false - # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.10 -yarn_mappings=1.21.10+build.2 -loader_version=0.17.3 -loom_version=1.12-SNAPSHOT +minecraft_version=26.1-snapshot-4 +loader_version=0.18.4 +loom_version=1.15-SNAPSHOT # Mod Properties -mod_version=1.0.0+1.21.10 +mod_version=1.0.1-beta+26.1-snapshots_fabric maven_group=me.imgalvin archives_base_name=auto-lan # Dependencies -fabric_version=0.137.0+1.21.10 \ No newline at end of file +fabric_api_version=0.142.2+26.1 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d4081da..19a6bde 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.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From d6555d135bc1df450d5abb5db273dcbe9cdba710 Mon Sep 17 00:00:00 2001 From: GalvinPython Date: Sun, 8 Feb 2026 11:55:06 +0000 Subject: [PATCH 2/5] backing up before moving to mixins --- gradle.properties | 7 ++++--- src/main/java/me/imgalvin/Autolan.java | 29 ++++++++++++++------------ src/main/resources/fabric.mod.json | 4 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/gradle.properties b/gradle.properties index 01fa9e8..d241af7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,14 +4,15 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=26.1-snapshot-4 + +minecraft_version=26.1-snapshot-6 loader_version=0.18.4 loom_version=1.15-SNAPSHOT # Mod Properties -mod_version=1.0.1-beta+26.1-snapshots_fabric +mod_version=1.1.1-beta+26.1-snapshots_fabric maven_group=me.imgalvin archives_base_name=auto-lan # Dependencies -fabric_api_version=0.142.2+26.1 \ No newline at end of file +fabric_api_version=0.143.2+26.1 \ No newline at end of file diff --git a/src/main/java/me/imgalvin/Autolan.java b/src/main/java/me/imgalvin/Autolan.java index f2cd263..55e2403 100644 --- a/src/main/java/me/imgalvin/Autolan.java +++ b/src/main/java/me/imgalvin/Autolan.java @@ -2,26 +2,29 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.text.Text; -import net.minecraft.world.GameMode; +import net.minecraft.client.server.IntegratedServer; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.GameType; -import static net.minecraft.util.NetworkUtils.findLocalPort; +import static net.minecraft.util.HttpUtil.getAvailablePort; public class Autolan implements ClientModInitializer { - private boolean opened = false; - @Override public void onInitializeClient() { + System.out.println("Autolan initialized!"); ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (!opened && client.player != null && client.getServer() != null) { - IntegratedServer server = client.getServer(); + System.out.println("Checking for player and server..."); + if (client.player != null && client.getCurrentServer() != null) { + IntegratedServer server = client.getSingleplayerServer(); + + System.out.println("Checking for LAN..."); + if (server == null) return; - if (server.isSingleplayer()) { - int port = findLocalPort(); - server.openToLan(GameMode.CREATIVE, true, port); - client.player.sendMessage(Text.of("§aOpened to LAN on port " + port), false); - opened = true; + System.out.println("Opening LAN server"); + if (server.isSingleplayer() && !server.isPublished()) { + int port = getAvailablePort(); + server.publishServer(GameType.CREATIVE, true, port); + client.player.displayClientMessage(Component.literal("§aOpened to LAN on port " + port), false); } } }); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 14f2516..cab9e6e 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -22,8 +22,8 @@ }, "depends": { "fabricloader": ">=0.16", - "minecraft": "1.21.10", - "java": ">=21", + "minecraft": "26.1-alpha.6", + "java": ">=25", "fabric-api": "*" } } \ No newline at end of file From fc7ae503475df78e29e2a8fb58967d94df727b67 Mon Sep 17 00:00:00 2001 From: GalvinPython Date: Sun, 8 Feb 2026 13:17:04 +0000 Subject: [PATCH 3/5] moved to mixins --- gradle.properties | 2 +- src/main/java/me/imgalvin/Autolan.java | 32 ++++++++-------- .../imgalvin/Mixin/PublishLANServerMixin.java | 38 +++++++++++++++++++ src/main/resources/autolan.client.mixins.json | 11 ++++++ src/main/resources/fabric.mod.json | 5 ++- 5 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java create mode 100644 src/main/resources/autolan.client.mixins.json diff --git a/gradle.properties b/gradle.properties index d241af7..66092a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.18.4 loom_version=1.15-SNAPSHOT # Mod Properties -mod_version=1.1.1-beta+26.1-snapshots_fabric +mod_version=1.0.1-beta+26.1-snapshots_fabric maven_group=me.imgalvin archives_base_name=auto-lan diff --git a/src/main/java/me/imgalvin/Autolan.java b/src/main/java/me/imgalvin/Autolan.java index 55e2403..620d59a 100644 --- a/src/main/java/me/imgalvin/Autolan.java +++ b/src/main/java/me/imgalvin/Autolan.java @@ -12,21 +12,21 @@ public class Autolan implements ClientModInitializer { @Override public void onInitializeClient() { System.out.println("Autolan initialized!"); - ClientTickEvents.END_CLIENT_TICK.register(client -> { - System.out.println("Checking for player and server..."); - if (client.player != null && client.getCurrentServer() != null) { - IntegratedServer server = client.getSingleplayerServer(); - - System.out.println("Checking for LAN..."); - if (server == null) return; - - System.out.println("Opening LAN server"); - if (server.isSingleplayer() && !server.isPublished()) { - int port = getAvailablePort(); - server.publishServer(GameType.CREATIVE, true, port); - client.player.displayClientMessage(Component.literal("§aOpened to LAN on port " + port), false); - } - } - }); +// ClientTickEvents.END_CLIENT_TICK.register(client -> { +// System.out.println("Checking for player and server..."); +// if (client.player != null && client.getCurrentServer() != null) { +// IntegratedServer server = client.getSingleplayerServer(); +// +// System.out.println("Checking for LAN..."); +// if (server == null) return; +// +// System.out.println("Opening LAN server"); +// if (server.isSingleplayer() && !server.isPublished()) { +// int port = getAvailablePort(); +// server.publishServer(GameType.CREATIVE, true, port); +// client.player.displayClientMessage(Component.literal("§aOpened to LAN on port " + port), false); +// } +// } +// }); } } diff --git a/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java b/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java new file mode 100644 index 0000000..98885fd --- /dev/null +++ b/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java @@ -0,0 +1,38 @@ +package me.imgalvin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.HttpUtil; +import net.minecraft.world.level.GameType; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftServer.class) +public abstract class PublishLANServerMixin { + @Shadow + public abstract boolean publishServer(@Nullable GameType gameMode, boolean allowCommands, int port); + + @Inject(at = @At("TAIL"), method = "loadLevel") + private void init(CallbackInfo info) { + // This code is injected into the start of MinecraftServer.loadLevel()V + // Wait until net.minecraft.client.Minecraft.getConnection() is not null + new Thread(() -> { + while (Minecraft.getInstance().getConnection() == null) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + int port = HttpUtil.getAvailablePort(); + publishServer(GameType.CREATIVE, true, port); + MinecraftServer server = (MinecraftServer) (Object) this; + server.getPlayerList().broadcastSystemMessage(Component.literal("§aOpened to LAN on port " + port), false); + }).start(); + } +} diff --git a/src/main/resources/autolan.client.mixins.json b/src/main/resources/autolan.client.mixins.json new file mode 100644 index 0000000..50065f6 --- /dev/null +++ b/src/main/resources/autolan.client.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "me.imgalvin.Mixin", + "compatibilityLevel": "JAVA_25", + "client": [ + "PublishLANServerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index cab9e6e..c6cd631 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -25,5 +25,8 @@ "minecraft": "26.1-alpha.6", "java": ">=25", "fabric-api": "*" - } + }, + "mixins": [ + "autolan.client.mixins.json" + ] } \ No newline at end of file From 425a85dd0d058c6bf64467ba790d59060f85d381 Mon Sep 17 00:00:00 2001 From: GalvinPython Date: Sun, 8 Feb 2026 13:17:30 +0000 Subject: [PATCH 4/5] remove old code --- src/main/java/me/imgalvin/Autolan.java | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/main/java/me/imgalvin/Autolan.java b/src/main/java/me/imgalvin/Autolan.java index 620d59a..fcb0d05 100644 --- a/src/main/java/me/imgalvin/Autolan.java +++ b/src/main/java/me/imgalvin/Autolan.java @@ -1,32 +1,10 @@ package me.imgalvin; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.minecraft.client.server.IntegratedServer; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.GameType; - -import static net.minecraft.util.HttpUtil.getAvailablePort; public class Autolan implements ClientModInitializer { @Override public void onInitializeClient() { System.out.println("Autolan initialized!"); -// ClientTickEvents.END_CLIENT_TICK.register(client -> { -// System.out.println("Checking for player and server..."); -// if (client.player != null && client.getCurrentServer() != null) { -// IntegratedServer server = client.getSingleplayerServer(); -// -// System.out.println("Checking for LAN..."); -// if (server == null) return; -// -// System.out.println("Opening LAN server"); -// if (server.isSingleplayer() && !server.isPublished()) { -// int port = getAvailablePort(); -// server.publishServer(GameType.CREATIVE, true, port); -// client.player.displayClientMessage(Component.literal("§aOpened to LAN on port " + port), false); -// } -// } -// }); } } From f0764990233c981a78eb2996ac4c9a8552a6a8ed Mon Sep 17 00:00:00 2001 From: GalvinPython Date: Sun, 8 Feb 2026 13:42:18 +0000 Subject: [PATCH 5/5] add logging & make mixin more thread safe --- src/main/java/me/imgalvin/Autolan.java | 8 ++- .../imgalvin/Mixin/PublishLANServerMixin.java | 60 ++++++++++++++----- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/main/java/me/imgalvin/Autolan.java b/src/main/java/me/imgalvin/Autolan.java index fcb0d05..98ee6a5 100644 --- a/src/main/java/me/imgalvin/Autolan.java +++ b/src/main/java/me/imgalvin/Autolan.java @@ -2,9 +2,15 @@ import net.fabricmc.api.ClientModInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class Autolan implements ClientModInitializer { + public static final String MOD_ID = "AutoLan"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + @Override public void onInitializeClient() { - System.out.println("Autolan initialized!"); + LOGGER.info("AutoLan initialized!"); } } diff --git a/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java b/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java index 98885fd..2b002a4 100644 --- a/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java +++ b/src/main/java/me/imgalvin/Mixin/PublishLANServerMixin.java @@ -6,33 +6,63 @@ import net.minecraft.util.HttpUtil; import net.minecraft.world.level.GameType; import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + @Mixin(MinecraftServer.class) public abstract class PublishLANServerMixin { @Shadow public abstract boolean publishServer(@Nullable GameType gameMode, boolean allowCommands, int port); + @Shadow + @Final + private static Logger LOGGER; + // Scheduler to check for connection readiness without blocking the main thread + @Unique + private static final ScheduledExecutorService SCHEDULER = Executors.newSingleThreadScheduledExecutor(); + + // Inject at the end of loadLevel @Inject(at = @At("TAIL"), method = "loadLevel") private void init(CallbackInfo info) { - // This code is injected into the start of MinecraftServer.loadLevel()V - // Wait until net.minecraft.client.Minecraft.getConnection() is not null - new Thread(() -> { - while (Minecraft.getInstance().getConnection() == null) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } + MinecraftServer server = (MinecraftServer) (Object) this; + attemptLanPublish(server); + } + + @Unique + private void attemptLanPublish(MinecraftServer server) { + // Schedule a check every 500ms + SCHEDULER.scheduleAtFixedRate(() -> { + // Check if the connection is ready + if (Minecraft.getInstance().getConnection() != null) { + // Back to the main server thread for the actual logic + server.execute(() -> { + int port = HttpUtil.getAvailablePort(); + boolean success = publishServer(GameType.CREATIVE, true, port); + + if (success) { + server.getPlayerList().broadcastSystemMessage( + Component.literal("§aOpened to LAN on port " + port), false); + LOGGER.info("Successfully opened to LAN on port {}", port); + } else { + server.getPlayerList().broadcastSystemMessage( + Component.literal("§cFailed to open to LAN!"), false); + LOGGER.error("Failed to open to LAN on port {}", port); + } + }); + + // End scheduler + throw new RuntimeException("attemptLanPublish Complete"); } - int port = HttpUtil.getAvailablePort(); - publishServer(GameType.CREATIVE, true, port); - MinecraftServer server = (MinecraftServer) (Object) this; - server.getPlayerList().broadcastSystemMessage(Component.literal("§aOpened to LAN on port " + port), false); - }).start(); + }, 0, 500, TimeUnit.MILLISECONDS); } -} +} \ No newline at end of file