From a9b414c675083b0124e60b1413689836570920ad Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Sun, 25 Oct 2020 17:29:19 +0100 Subject: [PATCH] Add LAN games support. --- .../platform/fabric/GeyserFabricMod.java | 36 +++++++---- .../fabric/GeyserServerPortGetter.java | 48 +++++++++++++++ .../mixin/client/IntegratedServerMixin.java | 59 +++++++++++++++++++ .../server/MinecraftDedicatedServerMixin.java | 58 ++++++++++++++++++ .../fabric/src/main/resources/fabric.mod.json | 7 ++- .../main/resources/geyser-fabric.mixins.json | 14 +++++ 6 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java create mode 100644 bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index b716e1a8b..dd5154267 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -28,7 +28,7 @@ package org.geysermc.platform.fabric; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; +import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; @@ -57,8 +57,9 @@ import java.nio.file.Path; import java.util.*; import java.util.function.Function; -@Environment(EnvType.SERVER) -public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBootstrap { +public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { + + private static GeyserFabricMod instance; private GeyserConnector connector; private Path dataFolder; @@ -71,8 +72,14 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo private IGeyserPingPassthrough geyserPingPassthrough; @Override - public void onInitializeServer() { + public void onInitialize() { + instance = this; + this.onEnable(); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { + // Set as an event so we can get the proper IP and port if needed + ServerLifecycleEvents.SERVER_STARTED.register(this::startGeyser); + } } @Override @@ -99,29 +106,27 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo if (server == null) { // Server has yet to start - // Set as an event so we can get the proper IP and port if needed - ServerLifecycleEvents.SERVER_STARTED.register((server) -> { - this.server = server; - startGeyser(); - }); - // Register onDisable so players are properly kicked ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); } else { // Server has started and this is a reload - startGeyser(); + startGeyser(this.server); } } /** * Initialize core Geyser. * A function, as it needs to be called in different places depending on if Geyser is being reloaded or not. + * + * @param server The minecraft server. */ - public void startGeyser() { + public void startGeyser(MinecraftServer server) { + this.server = server; + if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); String ip = server.getServerIp(); - int port = server.getServerPort(); + int port = ((GeyserServerPortGetter) server).geyser$getServerPort(); if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { this.geyserConfig.getRemote().setAddress(ip); } @@ -157,6 +162,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo connector.shutdown(); connector = null; } + this.server = null; } @Override @@ -212,4 +218,8 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo return file; } + + public static GeyserFabricMod getInstance() { + return instance; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java new file mode 100644 index 000000000..5af7775a8 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import net.minecraft.server.MinecraftServer; + +/** + * Represents a getter to the server port in the dedicated server and in the integrated server. + */ +public interface GeyserServerPortGetter { + /** + * Returns the server port. + * + * + * + * The reason is that {@link MinecraftServer#getServerPort()} doesn't return the LAN port if it's the integrated server, + * and changing the behavior of this method via a mixin should be avoided as it could have unexpected consequences. + * + * @return The server port. + */ + int geyser$getServerPort(); +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java new file mode 100644 index 000000000..a84f71110 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.mixin.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.world.GameMode; +import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.GeyserServerPortGetter; +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.CallbackInfoReturnable; + +@Environment(EnvType.CLIENT) +@Mixin(IntegratedServer.class) +public class IntegratedServerMixin implements GeyserServerPortGetter { + @Shadow + private int lanPort; + + @Inject(method = "openToLan", at = @At("RETURN")) + private void onOpenToLan(GameMode gameMode, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) { + if (cir.getReturnValueZ()) { + // If the LAN is opened, starts Geyser. + GeyserFabricMod.getInstance().startGeyser((MinecraftServer) (Object) this); + } + } + + @Override + public int geyser$getServerPort() { + return this.lanPort; + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java new file mode 100644 index 000000000..eec6af74f --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.mixin.server; + +import com.mojang.authlib.GameProfileRepository; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.datafixers.DataFixer; +import net.minecraft.resource.ResourcePackManager; +import net.minecraft.resource.ServerResourceManager; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.WorldGenerationProgressListenerFactory; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; +import net.minecraft.util.UserCache; +import net.minecraft.util.registry.DynamicRegistryManager; +import net.minecraft.world.SaveProperties; +import net.minecraft.world.level.storage.LevelStorage; +import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.spongepowered.asm.mixin.Mixin; + +import java.net.Proxy; + +@Mixin(MinecraftDedicatedServer.class) +public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter +{ + // Constructor to compile + public MinecraftDedicatedServerMixin(Thread thread, DynamicRegistryManager.Impl impl, LevelStorage.Session session, SaveProperties saveProperties, ResourcePackManager resourcePackManager, Proxy proxy, DataFixer dataFixer, ServerResourceManager serverResourceManager, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { + super(thread, impl, session, saveProperties, resourcePackManager, proxy, dataFixer, serverResourceManager, minecraftSessionService, gameProfileRepository, userCache, worldGenerationProgressListenerFactory); + } + + @Override + public int geyser$getServerPort() { + return this.getServerPort(); + } +} diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 1655cc212..55f5ceb70 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -13,12 +13,15 @@ }, "license": "MIT", "icon": "assets/fabric/icon.png", - "environment": "server", + "environment": "*", "entrypoints": { - "server": [ + "main": [ "org.geysermc.platform.fabric.GeyserFabricMod" ] }, + "mixins": [ + "geyser-fabric.mixins.json" + ], "depends": { "fabricloader": ">=0.10.1+build.209", "fabric": "*", diff --git a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json new file mode 100644 index 000000000..3965f9781 --- /dev/null +++ b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "org.geysermc.platform.fabric.mixin", + "compatibilityLevel": "JAVA_8", + "client": [ + "client.IntegratedServerMixin" + ], + "server": [ + "server.MinecraftDedicatedServerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +}