mirror of
				https://github.com/GeyserMC/Geyser.git
				synced 2024-08-14 23:57:35 +00:00 
			
		
		
		
	NeoForge Platform Support (#3781)
* Initial work on Forge platform * Rework modded platforms to use a common module * Add support for integrated worlds on modded platforms * Fix classload errors and move mixins to shared module * Fix Fabric mixins and check min height in mod world manager * Add Forge command support * Add back modrinth publishing * Don't apply application plugin to shared mod sources * Fix docs * Delete unused class * Clean up repositories * - Update to 1.20.2 - set custom refmap name - fixed console commands crashing the server (hasPermission now accepts CommandSourceStack instead of Player) - Forge wants fastutil relocated, so be it Current issues: - ClassNotFound exceptions with classes that are clearly present * - Fix ClassNotFound errors on Forge due to weird Classloader - Dont relocate gson * merge upstream * oh no * Bump lombok, architectury-loom * init: neoforge 1.20.4 support * NeoForge builds Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Archive neoforge artifacts * transformForge -> transformNeoForge * Neoforge boots! * Fix mixins on neoforge * Update build/pr file names * Update mods.toml to new neoforge standard * Fix refmap naming * more fixes - no need to include gson - cleanup nullable/nonnull annotations - add more info to geyser dumps on neoforge * yeet platform executor * yet another temp branch to figure out the runServer task * yeet transitive dependency, that cant be right * Attempt at getting the runServer task to work, part two * Revert the changes for the runServer task, try and shut down the injector * Remove spigot weird bug workaround, shut down properly Also add a compileOnly dependency for the mod module to get rid of spammy false warnings * Update to latest restart changes - fix duplicate nodes crashing neoforge - connector -> geyser in GeyserModCommandExecutor - create command manager early to fix issues with permission gather event * Consistent NeoForge spelling, move some dependencies to the version toml * Add lombok to version catalogue * Add plugins to version catalogue * revert move to buildSrc * Create `assets/geyser/icon.png` to reference icon from a single file on standalone/neoforge/fabric * add fabric permissions api to libs.versions.toml --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> Co-authored-by: onebeastchris <github@onechris.mozmail.com> Co-authored-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									aca368e332
								
							
						
					
					
						commit
						97fc2de42f
					
				
					 55 changed files with 1504 additions and 243 deletions
				
			
		
							
								
								
									
										22
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -47,7 +47,14 @@ jobs:
 | 
			
		|||
        if: success()
 | 
			
		||||
        with:
 | 
			
		||||
          name: Geyser Fabric
 | 
			
		||||
          path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
 | 
			
		||||
          path: bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
 | 
			
		||||
          if-no-files-found: error
 | 
			
		||||
      - name: Archive artifacts (Geyser NeoForge)
 | 
			
		||||
        uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
 | 
			
		||||
        if: success()
 | 
			
		||||
        with:
 | 
			
		||||
          name: Geyser NeoForge
 | 
			
		||||
          path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
 | 
			
		||||
          if-no-files-found: error
 | 
			
		||||
      - name: Archive artifacts (Geyser Standalone)
 | 
			
		||||
        uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +125,7 @@ jobs:
 | 
			
		|||
          echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
 | 
			
		||||
          rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
 | 
			
		||||
 | 
			
		||||
      - name: Publish to Modrinth
 | 
			
		||||
      - name: Publish to Modrinth (Fabric)
 | 
			
		||||
        uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
 | 
			
		||||
        if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
 | 
			
		||||
        env:
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +133,16 @@ jobs:
 | 
			
		|||
        with:
 | 
			
		||||
          arguments: fabric:modrinth
 | 
			
		||||
          gradle-home-cache-cleanup: true
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
      - name: Publish to Modrinth (NeoForge)
 | 
			
		||||
        uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
 | 
			
		||||
        if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
 | 
			
		||||
        env:
 | 
			
		||||
          MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
 | 
			
		||||
        with:
 | 
			
		||||
          arguments: neoforge:modrinth
 | 
			
		||||
          gradle-home-cache-cleanup: true
 | 
			
		||||
 | 
			
		||||
      - name: Notify Discord
 | 
			
		||||
        if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
 | 
			
		||||
        # See https://github.com/Tim203/actions-git-discord-webhook/commits
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								.github/workflows/pullrequest.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/pullrequest.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -57,7 +57,14 @@ jobs:
 | 
			
		|||
        if: success()
 | 
			
		||||
        with:
 | 
			
		||||
          name: Geyser Fabric
 | 
			
		||||
          path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
 | 
			
		||||
          path: geyser/bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
 | 
			
		||||
          if-no-files-found: error
 | 
			
		||||
      - name: Archive artifacts (Geyser NeoForge)
 | 
			
		||||
        uses: actions/upload-artifact@v3
 | 
			
		||||
        if: success()
 | 
			
		||||
        with:
 | 
			
		||||
          name: Geyser NeoForge
 | 
			
		||||
          path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
 | 
			
		||||
          if-no-files-found: error
 | 
			
		||||
      - name: Archive artifacts (Geyser Standalone)
 | 
			
		||||
        uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,4 +42,4 @@ public abstract class PathPackCodec extends PackCodec {
 | 
			
		|||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    public abstract Path path();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ public record PlatformType(String platformName) {
 | 
			
		|||
    public static final PlatformType ANDROID = new PlatformType("Android");
 | 
			
		||||
    public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
 | 
			
		||||
    public static final PlatformType FABRIC = new PlatformType("Fabric");
 | 
			
		||||
    public static final PlatformType NEOFORGE = new PlatformType("NeoForge");
 | 
			
		||||
    public static final PlatformType SPIGOT = new PlatformType("Spigot");
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
  "required": true,
 | 
			
		||||
  "package": "org.geysermc.geyser.platform.fabric.mixin",
 | 
			
		||||
  "compatibilityLevel": "JAVA_16",
 | 
			
		||||
  "refmap": "geyser-fabric-refmap.json",
 | 
			
		||||
  "client": [
 | 
			
		||||
    "client.IntegratedServerMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "server": [
 | 
			
		||||
    "server.MinecraftDedicatedServerMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "injectors": {
 | 
			
		||||
    "defaultRequire": 1
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								bootstrap/mod/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								bootstrap/mod/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
architectury {
 | 
			
		||||
    common("neoforge", "fabric")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
loom {
 | 
			
		||||
    mixin.defaultRefmapName.set("geyser-refmap.json")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    api(projects.core)
 | 
			
		||||
    compileOnly(libs.mixin)
 | 
			
		||||
 | 
			
		||||
    // Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
 | 
			
		||||
    compileOnly(libs.fabric.loader)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								bootstrap/mod/fabric/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								bootstrap/mod/fabric/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
plugins {
 | 
			
		||||
    application
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
architectury {
 | 
			
		||||
    platformSetupLoomIde()
 | 
			
		||||
    fabric()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    modImplementation(libs.fabric.loader)
 | 
			
		||||
    modApi(libs.fabric.api)
 | 
			
		||||
 | 
			
		||||
    api(project(":mod", configuration = "namedElements"))
 | 
			
		||||
    shadow(project(path = ":mod", configuration = "transformProductionFabric")) {
 | 
			
		||||
        isTransitive = false
 | 
			
		||||
    }
 | 
			
		||||
    shadow(projects.core) {
 | 
			
		||||
        exclude(group = "com.google.guava", module = "guava")
 | 
			
		||||
        exclude(group = "com.google.code.gson", module = "gson")
 | 
			
		||||
        exclude(group = "org.slf4j")
 | 
			
		||||
        exclude(group = "com.nukkitx.fastutil")
 | 
			
		||||
        exclude(group = "io.netty.incubator")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    modImplementation(libs.fabric.permissions)
 | 
			
		||||
    include(libs.fabric.permissions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
application {
 | 
			
		||||
    mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks {
 | 
			
		||||
    remapJar {
 | 
			
		||||
        archiveBaseName.set("Geyser-Fabric")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    remapModrinthJar {
 | 
			
		||||
        archiveBaseName.set("geyser-fabric")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
modrinth {
 | 
			
		||||
    loaders.add("fabric")
 | 
			
		||||
    dependencies {
 | 
			
		||||
        required.project("fabric-api")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								bootstrap/mod/fabric/gradle.properties
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								bootstrap/mod/fabric/gradle.properties
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
loom.platform=fabric
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.fabric;
 | 
			
		||||
 | 
			
		||||
import me.lucko.fabric.api.permissions.v0.Permissions;
 | 
			
		||||
import net.fabricmc.api.EnvType;
 | 
			
		||||
import net.fabricmc.api.ModInitializer;
 | 
			
		||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
 | 
			
		||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
 | 
			
		||||
import net.fabricmc.loader.api.FabricLoader;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {
 | 
			
		||||
 | 
			
		||||
    public GeyserFabricBootstrap() {
 | 
			
		||||
        super(new GeyserFabricPlatform());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onInitialize() {
 | 
			
		||||
        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((server) -> {
 | 
			
		||||
                this.setServer(server);
 | 
			
		||||
                onGeyserEnable();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // These are only registered once
 | 
			
		||||
        ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown());
 | 
			
		||||
        ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
 | 
			
		||||
 | 
			
		||||
        this.onGeyserInitialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
 | 
			
		||||
        return Permissions.check(source, permissionNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
 | 
			
		||||
        return Permissions.check(source, permissionNode, permissionLevel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,99 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.fabric;
 | 
			
		||||
 | 
			
		||||
import net.fabricmc.loader.api.FabricLoader;
 | 
			
		||||
import net.fabricmc.loader.api.ModContainer;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
			
		||||
import org.geysermc.geyser.api.util.PlatformType;
 | 
			
		||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricPlatform implements GeyserModPlatform {
 | 
			
		||||
    
 | 
			
		||||
    private final ModContainer mod;
 | 
			
		||||
 | 
			
		||||
    public GeyserFabricPlatform() {
 | 
			
		||||
        this.mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull PlatformType platformType() {
 | 
			
		||||
        return PlatformType.FABRIC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull String configPath() {
 | 
			
		||||
        return "Geyser-Fabric";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull Path dataFolder(@NonNull String modId) {
 | 
			
		||||
        return FabricLoader.getInstance().getConfigDir().resolve(modId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
 | 
			
		||||
        return new GeyserFabricDumpInfo(server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
 | 
			
		||||
        Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
 | 
			
		||||
        if (floodgate.isPresent()) {
 | 
			
		||||
            Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate");
 | 
			
		||||
            bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable InputStream resolveResource(@NonNull String resource) {
 | 
			
		||||
        // We need to handle this differently, because Fabric shares the classloader across multiple mods
 | 
			
		||||
        Path path = this.mod.findPath(resource).orElse(null);
 | 
			
		||||
        if (path == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            return path.getFileSystem()
 | 
			
		||||
                    .provider()
 | 
			
		||||
                    .newInputStream(path);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,18 +9,18 @@
 | 
			
		|||
  ],
 | 
			
		||||
  "contact": {
 | 
			
		||||
    "website": "${url}",
 | 
			
		||||
    "repo": "https://github.com/GeyserMC/Geyser-Fabric"
 | 
			
		||||
    "repo": "https://github.com/GeyserMC/Geyser"
 | 
			
		||||
  },
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "icon": "assets/geyser-fabric/icon.png",
 | 
			
		||||
  "icon": "assets/geyser/icon.png",
 | 
			
		||||
  "environment": "*",
 | 
			
		||||
  "entrypoints": {
 | 
			
		||||
    "main": [
 | 
			
		||||
        "org.geysermc.geyser.platform.fabric.GeyserFabricMod"
 | 
			
		||||
        "org.geysermc.geyser.platform.fabric.GeyserFabricBootstrap"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "mixins": [
 | 
			
		||||
    "geyser-fabric.mixins.json"
 | 
			
		||||
    "geyser.mixins.json"
 | 
			
		||||
  ],
 | 
			
		||||
  "depends": {
 | 
			
		||||
    "fabricloader": ">=0.15.2",
 | 
			
		||||
							
								
								
									
										52
									
								
								bootstrap/mod/neoforge/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								bootstrap/mod/neoforge/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
plugins {
 | 
			
		||||
    application
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
architectury {
 | 
			
		||||
    platformSetupLoomIde()
 | 
			
		||||
    neoForge()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    // See https://github.com/google/guava/issues/6618
 | 
			
		||||
    modules {
 | 
			
		||||
        module("com.google.guava:listenablefuture") {
 | 
			
		||||
          replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    neoForge(libs.neoforge.minecraft)
 | 
			
		||||
 | 
			
		||||
    api(project(":mod", configuration = "namedElements"))
 | 
			
		||||
    shadow(project(path = ":mod", configuration = "transformProductionNeoForge")) {
 | 
			
		||||
        isTransitive = false
 | 
			
		||||
    }
 | 
			
		||||
    shadow(projects.core) {
 | 
			
		||||
        exclude(group = "com.google.guava", module = "guava")
 | 
			
		||||
        exclude(group = "com.google.code.gson", module = "gson")
 | 
			
		||||
        exclude(group = "org.slf4j")
 | 
			
		||||
        exclude(group = "io.netty.incubator")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
application {
 | 
			
		||||
    mainClass.set("org.geysermc.geyser.platform.forge.GeyserNeoForgeMain")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks {
 | 
			
		||||
    shadowJar {
 | 
			
		||||
        relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    remapJar {
 | 
			
		||||
        archiveBaseName.set("Geyser-NeoForge")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    remapModrinthJar {
 | 
			
		||||
        archiveBaseName.set("geyser-neoforge")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
modrinth {
 | 
			
		||||
    loaders.add("neoforge")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								bootstrap/mod/neoforge/gradle.properties
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								bootstrap/mod/neoforge/gradle.properties
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
loom.platform=neoforge
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,83 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.fml.common.Mod;
 | 
			
		||||
import net.neoforged.fml.loading.FMLLoader;
 | 
			
		||||
import net.neoforged.neoforge.common.NeoForge;
 | 
			
		||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
 | 
			
		||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
 | 
			
		||||
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
 | 
			
		||||
 | 
			
		||||
@Mod(ModConstants.MOD_ID)
 | 
			
		||||
public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
 | 
			
		||||
 | 
			
		||||
    private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
 | 
			
		||||
 | 
			
		||||
    public GeyserNeoForgeBootstrap() {
 | 
			
		||||
        super(new GeyserNeoForgePlatform());
 | 
			
		||||
 | 
			
		||||
        if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) {
 | 
			
		||||
            // Set as an event so we can get the proper IP and port if needed
 | 
			
		||||
            NeoForge.EVENT_BUS.addListener(this::onServerStarted);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        NeoForge.EVENT_BUS.addListener(this::onServerStopping);
 | 
			
		||||
        NeoForge.EVENT_BUS.addListener(this::onPlayerJoin);
 | 
			
		||||
        NeoForge.EVENT_BUS.addListener(this.permissionHandler::onPermissionGather);
 | 
			
		||||
 | 
			
		||||
        this.onGeyserInitialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onServerStarted(ServerStartedEvent event) {
 | 
			
		||||
        this.setServer(event.getServer());
 | 
			
		||||
        this.onGeyserEnable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onServerStopping(ServerStoppingEvent event) {
 | 
			
		||||
        this.onGeyserShutdown();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
 | 
			
		||||
        GeyserModUpdateListener.onPlayReady(event.getEntity());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
 | 
			
		||||
        return this.permissionHandler.hasPermission(source, permissionNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
 | 
			
		||||
        return this.permissionHandler.hasPermission(source, permissionNode, permissionLevel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.neoforged.api.distmarker.Dist;
 | 
			
		||||
import net.neoforged.fml.ModList;
 | 
			
		||||
import net.neoforged.fml.loading.FMLLoader;
 | 
			
		||||
import net.neoforged.neoforgespi.language.IModInfo;
 | 
			
		||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
 | 
			
		||||
import org.geysermc.geyser.text.AsteriskSerializer;
 | 
			
		||||
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Getter
 | 
			
		||||
public class GeyserNeoForgeDumpInfo extends BootstrapDumpInfo {
 | 
			
		||||
 | 
			
		||||
    private final String platformName;
 | 
			
		||||
    private final String platformVersion;
 | 
			
		||||
    private final String minecraftVersion;
 | 
			
		||||
    private final Dist dist;
 | 
			
		||||
 | 
			
		||||
    @AsteriskSerializer.Asterisk(isIp = true)
 | 
			
		||||
    private final String serverIP;
 | 
			
		||||
    private final int serverPort;
 | 
			
		||||
    private final boolean onlineMode;
 | 
			
		||||
    private final List<ModInfo> mods;
 | 
			
		||||
 | 
			
		||||
    public GeyserNeoForgeDumpInfo(MinecraftServer server) {
 | 
			
		||||
        this.platformName = FMLLoader.launcherHandlerName();
 | 
			
		||||
        this.platformVersion = FMLLoader.versionInfo().neoForgeVersion();
 | 
			
		||||
        this.minecraftVersion = FMLLoader.versionInfo().mcVersion();
 | 
			
		||||
        this.dist = FMLLoader.getDist();
 | 
			
		||||
        this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp();
 | 
			
		||||
        this.serverPort = server.getPort();
 | 
			
		||||
        this.onlineMode = server.usesAuthentication();
 | 
			
		||||
        this.mods = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        for (IModInfo mod : ModList.get().getMods()) {
 | 
			
		||||
            this.mods.add(new ModInfo(
 | 
			
		||||
                    ModList.get().isLoaded(mod.getModId()),
 | 
			
		||||
                    mod.getModId(),
 | 
			
		||||
                    mod.getVersion().toString(),
 | 
			
		||||
                    mod.getModURL().map(URL::toString).orElse("")
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    @AllArgsConstructor
 | 
			
		||||
    public static class ModInfo {
 | 
			
		||||
        public boolean enabled;
 | 
			
		||||
        public String name;
 | 
			
		||||
        public String version;
 | 
			
		||||
        public String url;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
import org.geysermc.geyser.GeyserMain;
 | 
			
		||||
 | 
			
		||||
public class GeyserNeoForgeMain extends GeyserMain {
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        new GeyserNeoForgeMain().displayMessage();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPluginType() {
 | 
			
		||||
        return "NeoForge";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPluginFolder() {
 | 
			
		||||
        return "mods";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,149 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.server.level.ServerPlayer;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.PermissionAPI;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
 | 
			
		||||
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.geysermc.geyser.Constants;
 | 
			
		||||
import org.geysermc.geyser.GeyserImpl;
 | 
			
		||||
import org.geysermc.geyser.api.command.Command;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommandManager;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Constructor;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
public class GeyserNeoForgePermissionHandler {
 | 
			
		||||
 | 
			
		||||
    private static final Constructor<?> PERMISSION_NODE_CONSTRUCTOR;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        try {
 | 
			
		||||
            @SuppressWarnings("rawtypes")
 | 
			
		||||
            Constructor<PermissionNode> constructor = PermissionNode.class.getDeclaredConstructor(
 | 
			
		||||
                    String.class,
 | 
			
		||||
                    PermissionType.class,
 | 
			
		||||
                    PermissionNode.PermissionResolver.class,
 | 
			
		||||
                    PermissionDynamicContextKey[].class
 | 
			
		||||
            );
 | 
			
		||||
            constructor.setAccessible(true);
 | 
			
		||||
            PERMISSION_NODE_CONSTRUCTOR = constructor;
 | 
			
		||||
        } catch (NoSuchMethodException e) {
 | 
			
		||||
            throw new RuntimeException("Unable to construct PermissionNode!", e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final Map<String, PermissionNode<Boolean>> permissionNodes = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    public void onPermissionGather(PermissionGatherEvent.Nodes event) {
 | 
			
		||||
        this.registerNode(Constants.UPDATE_PERMISSION, event);
 | 
			
		||||
 | 
			
		||||
        GeyserCommandManager commandManager = GeyserImpl.getInstance().commandManager();
 | 
			
		||||
        for (Map.Entry<String, Command> entry : commandManager.commands().entrySet()) {
 | 
			
		||||
            Command command = entry.getValue();
 | 
			
		||||
 | 
			
		||||
            // Don't register aliases
 | 
			
		||||
            if (!command.name().equals(entry.getKey())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.registerNode(command.permission(), event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Map<String, Command> commands : commandManager.extensionCommands().values()) {
 | 
			
		||||
            for (Map.Entry<String, Command> entry : commands.entrySet()) {
 | 
			
		||||
                Command command = entry.getValue();
 | 
			
		||||
 | 
			
		||||
                // Don't register aliases
 | 
			
		||||
                if (!command.name().equals(entry.getKey())) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.registerNode(command.permission(), event);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
 | 
			
		||||
        PermissionNode<Boolean> node = this.permissionNodes.get(permissionNode);
 | 
			
		||||
        if (node == null) {
 | 
			
		||||
            GeyserImpl.getInstance().getLogger().warning("Unable to find permission node " + permissionNode);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PermissionAPI.getPermission((ServerPlayer) source, node);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
 | 
			
		||||
        if (!source.isPlayer()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        assert source.getPlayer() != null;
 | 
			
		||||
        boolean permission = this.hasPermission(source.getPlayer(), permissionNode);
 | 
			
		||||
        if (!permission) {
 | 
			
		||||
            return source.getPlayer().hasPermissions(permissionLevel);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void registerNode(String node, PermissionGatherEvent.Nodes event) {
 | 
			
		||||
        PermissionNode<Boolean> permissionNode = this.createNode(node);
 | 
			
		||||
 | 
			
		||||
        // NeoForge likes to crash if you try and register a duplicate node
 | 
			
		||||
        if (!event.getNodes().contains(permissionNode)) {
 | 
			
		||||
            event.addNodes(permissionNode);
 | 
			
		||||
            this.permissionNodes.put(node, permissionNode);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private PermissionNode<Boolean> createNode(String node) {
 | 
			
		||||
        // The typical constructors in PermissionNode require a
 | 
			
		||||
        // mod id, which means our permission nodes end up becoming
 | 
			
		||||
        // geyser_neoforge.<node> instead of just <node>. We work around
 | 
			
		||||
        // this by using reflection to access the constructor that
 | 
			
		||||
        // doesn't require a mod id or ResourceLocation.
 | 
			
		||||
        try {
 | 
			
		||||
            return (PermissionNode<Boolean>) PERMISSION_NODE_CONSTRUCTOR.newInstance(
 | 
			
		||||
                    node,
 | 
			
		||||
                    PermissionTypes.BOOLEAN,
 | 
			
		||||
                    (PermissionNode.PermissionResolver<Boolean>) (player, playerUUID, context) -> false,
 | 
			
		||||
                    new PermissionDynamicContextKey[0]
 | 
			
		||||
            );
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw new RuntimeException("Unable to create permission node " + node, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.neoforged.fml.loading.FMLPaths;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
			
		||||
import org.geysermc.geyser.GeyserBootstrap;
 | 
			
		||||
import org.geysermc.geyser.api.util.PlatformType;
 | 
			
		||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
 | 
			
		||||
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
 | 
			
		||||
public class GeyserNeoForgePlatform implements GeyserModPlatform {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull PlatformType platformType() {
 | 
			
		||||
        return PlatformType.NEOFORGE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull String configPath() {
 | 
			
		||||
        return "Geyser-NeoForge";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull Path dataFolder(@NonNull String modId) {
 | 
			
		||||
        return FMLPaths.CONFIGDIR.get().resolve(modId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
 | 
			
		||||
        return new GeyserNeoForgeDumpInfo(server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
 | 
			
		||||
        return false; // No Floodgate mod for NeoForge yet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable InputStream resolveResource(@NonNull String resource) {
 | 
			
		||||
        return GeyserBootstrap.class.getClassLoader().getResourceAsStream(resource);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.neoforge;
 | 
			
		||||
 | 
			
		||||
public class ModConstants {
 | 
			
		||||
    public static final String MOD_ID = "geyser_neoforge";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								bootstrap/mod/neoforge/src/main/resources/META-INF/mods.toml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
modLoader="javafml"
 | 
			
		||||
loaderVersion="[1,)"
 | 
			
		||||
license="MIT"
 | 
			
		||||
[[mods]]
 | 
			
		||||
modId="geyser_neoforge"
 | 
			
		||||
version="${version}"
 | 
			
		||||
displayName="Geyser"
 | 
			
		||||
displayURL="https://geysermc.org/"
 | 
			
		||||
logoFile= "../assets/geyser/icon.png"
 | 
			
		||||
authors="GeyserMC"
 | 
			
		||||
description="${description}"
 | 
			
		||||
[[mixins]]
 | 
			
		||||
config = "geyser.mixins.json"
 | 
			
		||||
[[dependencies.geyser_neoforge]]
 | 
			
		||||
    modId="neoforge"
 | 
			
		||||
    type="required"
 | 
			
		||||
    versionRange="[20.4.48-beta,)"
 | 
			
		||||
    ordering="NONE"
 | 
			
		||||
    side="BOTH"
 | 
			
		||||
[[dependencies.geyser_neoforge]]
 | 
			
		||||
    modId="minecraft"
 | 
			
		||||
    type="required"
 | 
			
		||||
    versionRange="[1.20,1.21)"
 | 
			
		||||
    ordering="NONE"
 | 
			
		||||
    side="BOTH"
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import io.netty.channel.ChannelFuture;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a getter to the server channels in the connection listener class.
 | 
			
		||||
 */
 | 
			
		||||
public interface GeyserChannelGetter {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the channels.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The channels.
 | 
			
		||||
     */
 | 
			
		||||
    List<ChannelFuture> geyser$getChannels();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,21 +23,17 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import com.mojang.brigadier.arguments.StringArgumentType;
 | 
			
		||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
import net.fabricmc.api.EnvType;
 | 
			
		||||
import net.fabricmc.api.ModInitializer;
 | 
			
		||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
 | 
			
		||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
 | 
			
		||||
import net.fabricmc.loader.api.FabricLoader;
 | 
			
		||||
import net.fabricmc.loader.api.ModContainer;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.commands.Commands;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import org.apache.logging.log4j.LogManager;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +42,6 @@ import org.geysermc.geyser.GeyserImpl;
 | 
			
		|||
import org.geysermc.geyser.GeyserLogger;
 | 
			
		||||
import org.geysermc.geyser.api.command.Command;
 | 
			
		||||
import org.geysermc.geyser.api.extension.Extension;
 | 
			
		||||
import org.geysermc.geyser.api.util.PlatformType;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommand;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommandManager;
 | 
			
		||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,8 +49,9 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo;
 | 
			
		|||
import org.geysermc.geyser.level.WorldManager;
 | 
			
		||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
 | 
			
		||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.command.GeyserModCommandExecutor;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.world.GeyserModWorldManager;
 | 
			
		||||
import org.geysermc.geyser.text.GeyserLocale;
 | 
			
		||||
import org.geysermc.geyser.util.FileUtils;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,58 +60,46 @@ import java.io.IOException;
 | 
			
		|||
import java.io.InputStream;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public abstract class GeyserModBootstrap implements GeyserBootstrap {
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    private static GeyserFabricMod instance;
 | 
			
		||||
    private static GeyserModBootstrap instance;
 | 
			
		||||
 | 
			
		||||
    private final GeyserModPlatform platform;
 | 
			
		||||
 | 
			
		||||
    private GeyserImpl geyser;
 | 
			
		||||
    private ModContainer mod;
 | 
			
		||||
    private Path dataFolder;
 | 
			
		||||
 | 
			
		||||
    @Setter
 | 
			
		||||
    private MinecraftServer server;
 | 
			
		||||
 | 
			
		||||
    private GeyserCommandManager geyserCommandManager;
 | 
			
		||||
    private GeyserFabricConfiguration geyserConfig;
 | 
			
		||||
    private GeyserFabricLogger geyserLogger;
 | 
			
		||||
    private GeyserModConfiguration geyserConfig;
 | 
			
		||||
    private GeyserModInjector geyserInjector;
 | 
			
		||||
    private GeyserModLogger geyserLogger;
 | 
			
		||||
    private IGeyserPingPassthrough geyserPingPassthrough;
 | 
			
		||||
    private WorldManager geyserWorldManager;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onInitialize() {
 | 
			
		||||
        instance = this;
 | 
			
		||||
        mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
 | 
			
		||||
        onGeyserInitialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onGeyserInitialize() {
 | 
			
		||||
        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((server) -> {
 | 
			
		||||
                this.server = server;
 | 
			
		||||
                onGeyserEnable();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // These are only registered once
 | 
			
		||||
        ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown());
 | 
			
		||||
        ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler));
 | 
			
		||||
 | 
			
		||||
        dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric");
 | 
			
		||||
        instance = this;
 | 
			
		||||
        dataFolder = this.platform.dataFolder(this.platform.configPath());
 | 
			
		||||
        GeyserLocale.init(this);
 | 
			
		||||
        if (!loadConfig()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
 | 
			
		||||
        this.geyserLogger = new GeyserModLogger(geyserConfig.isDebugMode());
 | 
			
		||||
        GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
 | 
			
		||||
        this.geyser = GeyserImpl.load(PlatformType.FABRIC, this);
 | 
			
		||||
        this.geyser = GeyserImpl.load(this.platform.platformType(), this);
 | 
			
		||||
 | 
			
		||||
        // Create command manager here, since the permission handler on neo needs it
 | 
			
		||||
        this.geyserCommandManager = new GeyserCommandManager(geyser);
 | 
			
		||||
        this.geyserCommandManager.init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onGeyserEnable() {
 | 
			
		||||
        if (GeyserImpl.getInstance().isReloading()) {
 | 
			
		||||
            if (!loadConfig()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,35 +107,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
            }
 | 
			
		||||
            this.geyserLogger.setDebug(geyserConfig.isDebugMode());
 | 
			
		||||
            GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.geyserCommandManager = new GeyserCommandManager(geyser);
 | 
			
		||||
            this.geyserCommandManager.init();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GeyserImpl.start();
 | 
			
		||||
 | 
			
		||||
        if (geyserConfig.isLegacyPingPassthrough()) {
 | 
			
		||||
            this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GeyserImpl.start();
 | 
			
		||||
 | 
			
		||||
        // No need to re-register commands, or re-recreate the world manager when reloading
 | 
			
		||||
        // No need to re-register commands, or try to re-inject
 | 
			
		||||
        if (GeyserImpl.getInstance().isReloading()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.geyserWorldManager = new GeyserFabricWorldManager(server);
 | 
			
		||||
        this.geyserWorldManager = new GeyserModWorldManager(server);
 | 
			
		||||
 | 
			
		||||
        // We want to do this late in the server startup process to allow other mods
 | 
			
		||||
        // To do their job injecting, then connect into *that*
 | 
			
		||||
        this.geyserInjector = new GeyserModInjector(server, this.platform);
 | 
			
		||||
        this.geyserInjector.initializeLocalChannel(this);
 | 
			
		||||
 | 
			
		||||
        // Start command building
 | 
			
		||||
        // Set just "geyser" as the help command
 | 
			
		||||
        GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
 | 
			
		||||
        GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(geyser,
 | 
			
		||||
                (GeyserCommand) geyser.commandManager().getCommands().get("help"));
 | 
			
		||||
        LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
 | 
			
		||||
 | 
			
		||||
        // Register all subcommands as valid
 | 
			
		||||
        for (Map.Entry<String, Command> command : geyser.commandManager().getCommands().entrySet()) {
 | 
			
		||||
            GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
 | 
			
		||||
            GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue());
 | 
			
		||||
            builder.then(Commands.literal(command.getKey())
 | 
			
		||||
                    .executes(executor)
 | 
			
		||||
                    // Could also test for Bedrock but depending on when this is called it may backfire
 | 
			
		||||
| 
						 | 
				
			
			@ -171,12 +157,12 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            // Register help command for just "/<extensionId>"
 | 
			
		||||
            GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
 | 
			
		||||
            GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(geyser,
 | 
			
		||||
                    (GeyserCommand) extensionCommands.get("help"));
 | 
			
		||||
            LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
 | 
			
		||||
 | 
			
		||||
            for (Map.Entry<String, Command> command : extensionCommands.entrySet()) {
 | 
			
		||||
                GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
 | 
			
		||||
                GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue());
 | 
			
		||||
                extCmdBuilder.then(Commands.literal(command.getKey())
 | 
			
		||||
                        .executes(executor)
 | 
			
		||||
                        .requires(executor::testPermission)
 | 
			
		||||
| 
						 | 
				
			
			@ -201,11 +187,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
            geyser.shutdown();
 | 
			
		||||
            geyser = null;
 | 
			
		||||
        }
 | 
			
		||||
        this.server = null;
 | 
			
		||||
        if (geyserInjector != null) {
 | 
			
		||||
            geyserInjector.shutdown();
 | 
			
		||||
            this.server = null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public GeyserConfiguration getGeyserConfig() {
 | 
			
		||||
    public GeyserModConfiguration getGeyserConfig() {
 | 
			
		||||
        return geyserConfig;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +225,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BootstrapDumpInfo getDumpInfo() {
 | 
			
		||||
        return new GeyserFabricDumpInfo(server);
 | 
			
		||||
        return this.platform.dumpInfo(this.server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -258,32 +247,19 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean testFloodgatePluginPresent() {
 | 
			
		||||
        Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
 | 
			
		||||
        if (floodgate.isPresent()) {
 | 
			
		||||
            geyserConfig.loadFloodgate(this, floodgate.orElse(null));
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
        return this.platform.testFloodgatePluginPresent(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public InputStream getResourceOrNull(String resource) {
 | 
			
		||||
        // We need to handle this differently, because Fabric shares the classloader across multiple mods
 | 
			
		||||
        Path path = this.mod.findPath(resource).orElse(null);
 | 
			
		||||
        if (path == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            return path.getFileSystem()
 | 
			
		||||
                    .provider()
 | 
			
		||||
                    .newInputStream(path);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return this.platform.resolveResource(resource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode);
 | 
			
		||||
 | 
			
		||||
    public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel);
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
 | 
			
		||||
    private boolean loadConfig() {
 | 
			
		||||
        try {
 | 
			
		||||
| 
						 | 
				
			
			@ -294,10 +270,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
 | 
			
		|||
 | 
			
		||||
            File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
 | 
			
		||||
                    (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
 | 
			
		||||
            this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class);
 | 
			
		||||
            this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (IOException ex) {
 | 
			
		||||
            LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
 | 
			
		||||
            LogManager.getLogger("geyser").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
 | 
			
		||||
            ex.printStackTrace();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2021 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.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import io.netty.channel.ChannelHandlerContext;
 | 
			
		||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
 | 
			
		||||
import io.netty.channel.ChannelPromise;
 | 
			
		||||
import net.minecraft.network.protocol.login.ClientboundGameProfilePacket;
 | 
			
		||||
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients
 | 
			
		||||
 * that won't be receiving the data over the network.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * As of 1.8 - 1.17.1, compression is enabled in the Netty pipeline by adding a listener after a packet is written.
 | 
			
		||||
 * If we simply "cancel" or don't forward the packet, then the listener is never called.
 | 
			
		||||
 */
 | 
			
		||||
public class GeyserModCompressionDisabler extends ChannelOutboundHandlerAdapter {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
 | 
			
		||||
        Class<?> msgClass = msg.getClass();
 | 
			
		||||
        // Don't let any compression packet get through
 | 
			
		||||
        if (!ClientboundLoginCompressionPacket.class.isAssignableFrom(msgClass)) {
 | 
			
		||||
            if (ClientboundGameProfilePacket.class.isAssignableFrom(msgClass)) {
 | 
			
		||||
 | 
			
		||||
                // We're past the point that a compression packet can be sent, so we can safely yeet ourselves away
 | 
			
		||||
                ctx.channel().pipeline().remove(this);
 | 
			
		||||
            }
 | 
			
		||||
            super.write(ctx, msg, promise);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,23 +23,20 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnore;
 | 
			
		||||
import net.fabricmc.loader.api.FabricLoader;
 | 
			
		||||
import net.fabricmc.loader.api.ModContainer;
 | 
			
		||||
import org.geysermc.geyser.FloodgateKeyLoader;
 | 
			
		||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
 | 
			
		||||
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricConfiguration extends GeyserJacksonConfiguration {
 | 
			
		||||
public class GeyserModConfiguration extends GeyserJacksonConfiguration {
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    private Path floodgateKeyPath;
 | 
			
		||||
 | 
			
		||||
    public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) {
 | 
			
		||||
    public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
 | 
			
		||||
        Path geyserDataFolder = geyser.getConfigFolder();
 | 
			
		||||
        Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
 | 
			
		||||
 | 
			
		||||
        floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,156 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import io.netty.bootstrap.ServerBootstrap;
 | 
			
		||||
import io.netty.channel.Channel;
 | 
			
		||||
import io.netty.channel.ChannelFuture;
 | 
			
		||||
import io.netty.channel.ChannelHandler;
 | 
			
		||||
import io.netty.channel.ChannelInitializer;
 | 
			
		||||
import io.netty.channel.DefaultEventLoopGroup;
 | 
			
		||||
import io.netty.channel.local.LocalAddress;
 | 
			
		||||
import io.netty.util.concurrent.DefaultThreadFactory;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.server.network.ServerConnectionListener;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.geysermc.geyser.GeyserBootstrap;
 | 
			
		||||
import org.geysermc.geyser.GeyserImpl;
 | 
			
		||||
import org.geysermc.geyser.network.netty.GeyserInjector;
 | 
			
		||||
import org.geysermc.geyser.network.netty.LocalServerChannelWrapper;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class GeyserModInjector extends GeyserInjector {
 | 
			
		||||
 | 
			
		||||
    private final MinecraftServer server;
 | 
			
		||||
    private final GeyserModPlatform platform;
 | 
			
		||||
    private DefaultEventLoopGroup eventLoopGroup;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to uninject ourselves on shutdown.
 | 
			
		||||
     */
 | 
			
		||||
    private List<ChannelFuture> allServerChannels;
 | 
			
		||||
 | 
			
		||||
    public GeyserModInjector(MinecraftServer server, GeyserModPlatform platform) {
 | 
			
		||||
        this.server = server;
 | 
			
		||||
        this.platform = platform;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception {
 | 
			
		||||
        ServerConnectionListener connection = this.server.getConnection();
 | 
			
		||||
 | 
			
		||||
        // Find the channel that Minecraft uses to listen to connections
 | 
			
		||||
        ChannelFuture listeningChannel = null;
 | 
			
		||||
        this.allServerChannels = ((GeyserChannelGetter) connection).geyser$getChannels();
 | 
			
		||||
        for (ChannelFuture o : allServerChannels) {
 | 
			
		||||
            listeningChannel = o;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (listeningChannel == null) {
 | 
			
		||||
            throw new RuntimeException("Unable to find listening channel!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Making this a function prevents childHandler from being treated as a non-final variable
 | 
			
		||||
        ChannelInitializer<Channel> childHandler = getChildHandler(bootstrap, listeningChannel);
 | 
			
		||||
        // This method is what initializes the connection in Java Edition, after Netty is all set.
 | 
			
		||||
        Method initChannel = childHandler.getClass().getDeclaredMethod("initChannel", Channel.class);
 | 
			
		||||
        initChannel.setAccessible(true);
 | 
			
		||||
 | 
			
		||||
        // Separate variable so we can shut it down later
 | 
			
		||||
        eventLoopGroup = new DefaultEventLoopGroup(0, new DefaultThreadFactory("Geyser " + this.platform.platformType().platformName() + " connection thread", Thread.MAX_PRIORITY));
 | 
			
		||||
        ChannelFuture channelFuture = (new ServerBootstrap()
 | 
			
		||||
                .channel(LocalServerChannelWrapper.class)
 | 
			
		||||
                .childHandler(new ChannelInitializer<>() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    protected void initChannel(@NonNull Channel ch) throws Exception {
 | 
			
		||||
                        initChannel.invoke(childHandler, ch);
 | 
			
		||||
 | 
			
		||||
                        if (bootstrap.getGeyserConfig().isDisableCompression()) {
 | 
			
		||||
                            ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserModCompressionDisabler());
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
                // Set to MAX_PRIORITY as MultithreadEventLoopGroup#newDefaultThreadFactory which DefaultEventLoopGroup implements does by default
 | 
			
		||||
                .group(eventLoopGroup)
 | 
			
		||||
                .localAddress(LocalAddress.ANY))
 | 
			
		||||
                .bind()
 | 
			
		||||
                .syncUninterruptibly();
 | 
			
		||||
        // We don't need to add to the list, but plugins like ProtocolSupport and ProtocolLib that add to the main pipeline
 | 
			
		||||
        // will work when we add to the list.
 | 
			
		||||
        allServerChannels.add(channelFuture);
 | 
			
		||||
        this.localChannel = channelFuture;
 | 
			
		||||
        this.serverSocketAddress = channelFuture.channel().localAddress();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private ChannelInitializer<Channel> getChildHandler(GeyserBootstrap bootstrap, ChannelFuture listeningChannel) {
 | 
			
		||||
        List<String> names = listeningChannel.channel().pipeline().names();
 | 
			
		||||
        ChannelInitializer<Channel> childHandler = null;
 | 
			
		||||
        for (String name : names) {
 | 
			
		||||
            ChannelHandler handler = listeningChannel.channel().pipeline().get(name);
 | 
			
		||||
            try {
 | 
			
		||||
                Field childHandlerField = handler.getClass().getDeclaredField("childHandler");
 | 
			
		||||
                childHandlerField.setAccessible(true);
 | 
			
		||||
                childHandler = (ChannelInitializer<Channel>) childHandlerField.get(handler);
 | 
			
		||||
                break;
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                if (bootstrap.getGeyserConfig().isDebugMode()) {
 | 
			
		||||
                    bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
 | 
			
		||||
                    e.printStackTrace();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (childHandler == null) {
 | 
			
		||||
            throw new RuntimeException();
 | 
			
		||||
        }
 | 
			
		||||
        return childHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void shutdown() {
 | 
			
		||||
        if (this.allServerChannels != null) {
 | 
			
		||||
            this.allServerChannels.remove(this.localChannel);
 | 
			
		||||
            this.allServerChannels = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (eventLoopGroup != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                eventLoopGroup.shutdownGracefully().sync();
 | 
			
		||||
                eventLoopGroup = null;
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                GeyserImpl.getInstance().getLogger().error("Unable to shut down injector! " + e.getMessage());
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.shutdown();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import net.kyori.adventure.text.Component;
 | 
			
		||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
 | 
			
		||||
| 
						 | 
				
			
			@ -32,12 +32,12 @@ import org.apache.logging.log4j.Logger;
 | 
			
		|||
import org.geysermc.geyser.GeyserLogger;
 | 
			
		||||
import org.geysermc.geyser.text.ChatColor;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricLogger implements GeyserLogger {
 | 
			
		||||
    private final Logger logger = LogManager.getLogger("geyser-fabric");
 | 
			
		||||
public class GeyserModLogger implements GeyserLogger {
 | 
			
		||||
    private final Logger logger = LogManager.getLogger("geyser");
 | 
			
		||||
 | 
			
		||||
    private boolean debug;
 | 
			
		||||
 | 
			
		||||
    public GeyserFabricLogger(boolean isDebug) {
 | 
			
		||||
    public GeyserModLogger(boolean isDebug) {
 | 
			
		||||
        debug = isDebug;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ public class GeyserFabricLogger implements GeyserLogger {
 | 
			
		|||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void sendMessage(Component message) {
 | 
			
		||||
        // As of Java Edition 1.19.2, Fabric's console doesn't natively support legacy format
 | 
			
		||||
        // As of Java Edition 1.19.2, Minecraft's console doesn't natively support legacy format
 | 
			
		||||
        String flattened = LegacyComponentSerializer.legacySection().serialize(message);
 | 
			
		||||
        // Add the reset at the end, or else format will persist... forever.
 | 
			
		||||
        // https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
 | 
			
		||||
| 
						 | 
				
			
			@ -23,21 +23,22 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import me.lucko.fabric.api.permissions.v0.Permissions;
 | 
			
		||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import org.geysermc.geyser.Constants;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.command.FabricCommandSender;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.command.ModCommandSender;
 | 
			
		||||
import org.geysermc.geyser.util.VersionCheckUtils;
 | 
			
		||||
 | 
			
		||||
public final class GeyserFabricUpdateListener {
 | 
			
		||||
    public static void onPlayReady(ServerGamePacketListenerImpl handler) {
 | 
			
		||||
        if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) {
 | 
			
		||||
            VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack()));
 | 
			
		||||
public final class GeyserModUpdateListener {
 | 
			
		||||
    public static void onPlayReady(Player player) {
 | 
			
		||||
        CommandSourceStack stack = player.createCommandSourceStack();
 | 
			
		||||
        if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION, 2)) {
 | 
			
		||||
            VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSender(stack));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private GeyserFabricUpdateListener() {
 | 
			
		||||
    private GeyserModUpdateListener() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric;
 | 
			
		||||
package org.geysermc.geyser.platform.mod;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import net.kyori.adventure.text.Component;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,10 +39,11 @@ import net.minecraft.network.protocol.status.ServerStatusPacketListener;
 | 
			
		|||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
			
		||||
import org.geysermc.geyser.GeyserLogger;
 | 
			
		||||
import org.geysermc.geyser.ping.GeyserPingInfo;
 | 
			
		||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.net.InetSocketAddress;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +101,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void send(Packet<?> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
 | 
			
		||||
        public void send(@NonNull Packet<?> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
 | 
			
		||||
            if (packet instanceof ClientboundStatusResponsePacket statusResponse) {
 | 
			
		||||
                status = statusResponse.status();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -23,31 +23,31 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric.command;
 | 
			
		||||
package org.geysermc.geyser.platform.mod.command;
 | 
			
		||||
 | 
			
		||||
import com.mojang.brigadier.Command;
 | 
			
		||||
import com.mojang.brigadier.context.CommandContext;
 | 
			
		||||
import me.lucko.fabric.api.permissions.v0.Permissions;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import org.geysermc.geyser.GeyserImpl;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommand;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.session.GeyserSession;
 | 
			
		||||
import org.geysermc.geyser.text.ChatColor;
 | 
			
		||||
import org.geysermc.geyser.text.GeyserLocale;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
 | 
			
		||||
public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
 | 
			
		||||
    private final GeyserCommand command;
 | 
			
		||||
 | 
			
		||||
    public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
 | 
			
		||||
        super(connector, Collections.singletonMap(command.name(), command));
 | 
			
		||||
    public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) {
 | 
			
		||||
        super(geyser, Collections.singletonMap(command.name(), command));
 | 
			
		||||
        this.command = command;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean testPermission(CommandSourceStack source) {
 | 
			
		||||
        return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
 | 
			
		||||
        return GeyserModBootstrap.getInstance().hasPermission(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
 | 
			
		|||
 | 
			
		||||
    public int runWithArgs(CommandContext<CommandSourceStack> context, String args) {
 | 
			
		||||
        CommandSourceStack source = context.getSource();
 | 
			
		||||
        FabricCommandSender sender = new FabricCommandSender(source);
 | 
			
		||||
        ModCommandSender sender = new ModCommandSender(source);
 | 
			
		||||
        GeyserSession session = getGeyserSession(sender);
 | 
			
		||||
        if (!testPermission(source)) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
 | 
			
		||||
| 
						 | 
				
			
			@ -23,9 +23,8 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric.command;
 | 
			
		||||
package org.geysermc.geyser.platform.mod.command;
 | 
			
		||||
 | 
			
		||||
import me.lucko.fabric.api.permissions.v0.Permissions;
 | 
			
		||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,15 +32,16 @@ import net.minecraft.server.level.ServerPlayer;
 | 
			
		|||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.geysermc.geyser.GeyserImpl;
 | 
			
		||||
import org.geysermc.geyser.command.GeyserCommandSource;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.text.ChatColor;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
public class FabricCommandSender implements GeyserCommandSource {
 | 
			
		||||
public class ModCommandSender implements GeyserCommandSource {
 | 
			
		||||
 | 
			
		||||
    private final CommandSourceStack source;
 | 
			
		||||
 | 
			
		||||
    public FabricCommandSender(CommandSourceStack source) {
 | 
			
		||||
    public ModCommandSender(CommandSourceStack source) {
 | 
			
		||||
        this.source = source;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +76,6 @@ public class FabricCommandSender implements GeyserCommandSource {
 | 
			
		|||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasPermission(String permission) {
 | 
			
		||||
        return Permissions.check(source, permission, source.getServer().getOperatorUserPermissionLevel());
 | 
			
		||||
        return GeyserModBootstrap.getInstance().hasPermission(source, permission, source.getServer().getOperatorUserPermissionLevel());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
 | 
			
		||||
 * Copyright (c) 2019-2023 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
 | 
			
		||||
| 
						 | 
				
			
			@ -23,18 +23,16 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric.mixin.client;
 | 
			
		||||
package org.geysermc.geyser.platform.mod.mixin.client;
 | 
			
		||||
 | 
			
		||||
import net.fabricmc.api.EnvType;
 | 
			
		||||
import net.fabricmc.api.Environment;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
import net.minecraft.client.server.IntegratedServer;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.world.level.GameType;
 | 
			
		||||
import org.geysermc.geyser.GeyserImpl;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
 | 
			
		||||
import org.geysermc.geyser.text.GeyserLocale;
 | 
			
		||||
import org.spongepowered.asm.mixin.Final;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +43,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 | 
			
		|||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
@Environment(EnvType.CLIENT)
 | 
			
		||||
@Mixin(IntegratedServer.class)
 | 
			
		||||
public class IntegratedServerMixin implements GeyserServerPortGetter {
 | 
			
		||||
    @Shadow
 | 
			
		||||
| 
						 | 
				
			
			@ -57,8 +54,8 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
 | 
			
		|||
    private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
 | 
			
		||||
        if (cir.getReturnValueZ()) {
 | 
			
		||||
            // If the LAN is opened, starts Geyser.
 | 
			
		||||
            GeyserFabricMod.getInstance().setServer((MinecraftServer) (Object) this);
 | 
			
		||||
            GeyserFabricMod.getInstance().onGeyserEnable();
 | 
			
		||||
            GeyserModBootstrap.getInstance().setServer((MinecraftServer) (Object) this);
 | 
			
		||||
            GeyserModBootstrap.getInstance().onGeyserEnable();
 | 
			
		||||
            // Ensure player locale has been loaded, in case it's different from Java system language
 | 
			
		||||
            GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
 | 
			
		||||
            // Give indication that Geyser is loaded
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
 | 
			
		||||
 * Copyright (c) 2019-2023 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
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric.mixin.server;
 | 
			
		||||
package org.geysermc.geyser.platform.mod.mixin.server;
 | 
			
		||||
 | 
			
		||||
import com.mojang.datafixers.DataFixer;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,14 +33,14 @@ import net.minecraft.server.dedicated.DedicatedServer;
 | 
			
		|||
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
 | 
			
		||||
import net.minecraft.server.packs.repository.PackRepository;
 | 
			
		||||
import net.minecraft.world.level.storage.LevelStorageSource;
 | 
			
		||||
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
 | 
			
		||||
import java.net.Proxy;
 | 
			
		||||
 | 
			
		||||
@Mixin(DedicatedServer.class)
 | 
			
		||||
public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
 | 
			
		||||
    public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
 | 
			
		||||
public abstract class DedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
 | 
			
		||||
    public DedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
 | 
			
		||||
        super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.mod.mixin.server;
 | 
			
		||||
 | 
			
		||||
import io.netty.channel.ChannelFuture;
 | 
			
		||||
import net.minecraft.server.network.ServerConnectionListener;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserChannelGetter;
 | 
			
		||||
import org.spongepowered.asm.mixin.Final;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
import org.spongepowered.asm.mixin.Shadow;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Mixin(ServerConnectionListener.class)
 | 
			
		||||
public abstract class ServerConnectionListenerMixin implements GeyserChannelGetter {
 | 
			
		||||
 | 
			
		||||
    @Shadow @Final private List<ChannelFuture> channels;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<ChannelFuture> geyser$getChannels() {
 | 
			
		||||
        return this.channels;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019-2023 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.geyser.platform.mod.platform;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.Nullable;
 | 
			
		||||
import org.geysermc.geyser.api.util.PlatformType;
 | 
			
		||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface which holds common methods that have different
 | 
			
		||||
 * APIs on their respective mod platforms.
 | 
			
		||||
 */
 | 
			
		||||
public interface GeyserModPlatform {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the {@link PlatformType} of the mod platform.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the platform type of the mod platform
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    PlatformType platformType();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the config path of the mod platform.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the config path of the mod platform
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    String configPath();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the data folder of the mod platform.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the data folder of the mod platform
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    Path dataFolder(@NonNull String modId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the dump info of the mod platform.
 | 
			
		||||
     *
 | 
			
		||||
     * @param server the server to get the dump info from
 | 
			
		||||
     * @return the dump info of the mod platform
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tests if the Floodgate plugin is present on the mod platform.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if the Floodgate plugin is present on the mod platform, {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resolves a resource from the mod jar.
 | 
			
		||||
     *
 | 
			
		||||
     * @param resource the name of the resource
 | 
			
		||||
     * @return the input stream of the resource
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    InputStream resolveResource(@NonNull String resource);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,22 +23,41 @@
 | 
			
		|||
 * @link https://github.com/GeyserMC/Geyser
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.geysermc.geyser.platform.fabric.world;
 | 
			
		||||
package org.geysermc.geyser.platform.mod.world;
 | 
			
		||||
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
 | 
			
		||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
 | 
			
		||||
import me.lucko.fabric.api.permissions.v0.Permissions;
 | 
			
		||||
import net.minecraft.SharedConstants;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.nbt.*;
 | 
			
		||||
import net.minecraft.nbt.ByteArrayTag;
 | 
			
		||||
import net.minecraft.nbt.ByteTag;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.nbt.DoubleTag;
 | 
			
		||||
import net.minecraft.nbt.EndTag;
 | 
			
		||||
import net.minecraft.nbt.FloatTag;
 | 
			
		||||
import net.minecraft.nbt.IntArrayTag;
 | 
			
		||||
import net.minecraft.nbt.IntTag;
 | 
			
		||||
import net.minecraft.nbt.ListTag;
 | 
			
		||||
import net.minecraft.nbt.LongArrayTag;
 | 
			
		||||
import net.minecraft.nbt.LongTag;
 | 
			
		||||
import net.minecraft.nbt.ShortTag;
 | 
			
		||||
import net.minecraft.nbt.StringTag;
 | 
			
		||||
import net.minecraft.nbt.Tag;
 | 
			
		||||
import net.minecraft.nbt.TagVisitor;
 | 
			
		||||
import net.minecraft.server.MinecraftServer;
 | 
			
		||||
import net.minecraft.server.level.ServerPlayer;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.WritableBookItem;
 | 
			
		||||
import net.minecraft.world.item.WrittenBookItem;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BannerBlockEntity;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
			
		||||
import net.minecraft.world.level.block.entity.LecternBlockEntity;
 | 
			
		||||
import net.minecraft.world.level.chunk.ChunkAccess;
 | 
			
		||||
import net.minecraft.world.level.chunk.ChunkStatus;
 | 
			
		||||
import net.minecraft.world.level.chunk.LevelChunk;
 | 
			
		||||
import net.minecraft.world.level.chunk.LevelChunkSection;
 | 
			
		||||
import org.checkerframework.checker.nullness.qual.NonNull;
 | 
			
		||||
import org.cloudburstmc.math.vector.Vector3i;
 | 
			
		||||
import org.cloudburstmc.nbt.NbtMap;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +65,8 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
 | 
			
		|||
import org.cloudburstmc.nbt.NbtType;
 | 
			
		||||
import org.geysermc.erosion.util.LecternUtils;
 | 
			
		||||
import org.geysermc.geyser.level.GeyserWorldManager;
 | 
			
		||||
import org.geysermc.geyser.network.GameProtocol;
 | 
			
		||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
 | 
			
		||||
import org.geysermc.geyser.session.GeyserSession;
 | 
			
		||||
import org.geysermc.geyser.util.BlockEntityUtils;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,13 +75,54 @@ import java.util.List;
 | 
			
		|||
import java.util.Objects;
 | 
			
		||||
import java.util.concurrent.CompletableFuture;
 | 
			
		||||
 | 
			
		||||
public class GeyserFabricWorldManager extends GeyserWorldManager {
 | 
			
		||||
public class GeyserModWorldManager extends GeyserWorldManager {
 | 
			
		||||
    private final MinecraftServer server;
 | 
			
		||||
 | 
			
		||||
    public GeyserFabricWorldManager(MinecraftServer server) {
 | 
			
		||||
    public GeyserModWorldManager(MinecraftServer server) {
 | 
			
		||||
        this.server = server;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getBlockAt(GeyserSession session, int x, int y, int z) {
 | 
			
		||||
        // If the protocol version of Geyser and the server are not the
 | 
			
		||||
        // same, fallback to the chunk cache. May be able to update this
 | 
			
		||||
        // in the future to use ViaVersion however, like Spigot does.
 | 
			
		||||
        if (SharedConstants.getCurrentVersion().getProtocolVersion() != GameProtocol.getJavaProtocolVersion()) {
 | 
			
		||||
            return super.getBlockAt(session, x, y, z);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ServerPlayer player = this.getPlayer(session);
 | 
			
		||||
        if (player == null) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Level level = player.level();
 | 
			
		||||
        if (y < level.getMinBuildHeight()) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ChunkAccess chunk = level.getChunkSource().getChunk(x >> 4, z >> 4, ChunkStatus.FULL, false);
 | 
			
		||||
        if (chunk == null) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int worldOffset = level.getMinBuildHeight() >> 4;
 | 
			
		||||
        int chunkOffset = (y >> 4) - worldOffset;
 | 
			
		||||
        if (chunkOffset < chunk.getSections().length) {
 | 
			
		||||
            LevelChunkSection section = chunk.getSections()[chunkOffset];
 | 
			
		||||
            if (section != null && !section.hasOnlyAir()) {
 | 
			
		||||
                return Block.getId(section.getBlockState(x & 15, y & 15, z & 15));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean hasOwnChunkCache() {
 | 
			
		||||
        return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean shouldExpectLecternHandled(GeyserSession session) {
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +216,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
 | 
			
		|||
    @Override
 | 
			
		||||
    public boolean hasPermission(GeyserSession session, String permission) {
 | 
			
		||||
        ServerPlayer player = getPlayer(session);
 | 
			
		||||
        return Permissions.check(player, permission);
 | 
			
		||||
        return GeyserModBootstrap.getInstance().hasPermission(player, permission);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
							
								
								
									
										18
									
								
								bootstrap/mod/src/main/resources/geyser.mixins.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								bootstrap/mod/src/main/resources/geyser.mixins.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
{
 | 
			
		||||
  "required": true,
 | 
			
		||||
  "minVersion": "0.8",
 | 
			
		||||
  "package": "org.geysermc.geyser.platform.mod.mixin",
 | 
			
		||||
  "compatibilityLevel": "JAVA_17",
 | 
			
		||||
  "mixins": [
 | 
			
		||||
    "server.ServerConnectionListenerMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "server": [
 | 
			
		||||
    "server.DedicatedServerMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "client": [
 | 
			
		||||
    "client.IntegratedServerMixin"
 | 
			
		||||
  ],
 | 
			
		||||
  "injectors": {
 | 
			
		||||
    "defaultRequire": 1
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ public class GeyserStandaloneGUI {
 | 
			
		|||
        Container cp = frame.getContentPane();
 | 
			
		||||
 | 
			
		||||
        // Fetch and set the icon for the frame
 | 
			
		||||
        URL image = getClass().getClassLoader().getResource("icon.png");
 | 
			
		||||
        URL image = getClass().getClassLoader().getResource("assets/geyser/icon.png");
 | 
			
		||||
        if (image != null) {
 | 
			
		||||
            ImageIcon icon = new ImageIcon(image);
 | 
			
		||||
            frame.setIconImage(icon.getImage());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,14 +4,17 @@ plugins {
 | 
			
		|||
 | 
			
		||||
repositories {
 | 
			
		||||
    gradlePluginPortal()
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-snapshots")
 | 
			
		||||
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-snapshots/")
 | 
			
		||||
    maven("https://maven.fabricmc.net/")
 | 
			
		||||
    maven("https://maven.neoforged.net/releases")
 | 
			
		||||
    maven("https://maven.architectury.dev/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation("net.kyori", "indra-common", "3.1.1")
 | 
			
		||||
    implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
 | 
			
		||||
 | 
			
		||||
    // Within the gradle plugin classpath, there is a version conflict between loom and some other
 | 
			
		||||
    // plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
 | 
			
		||||
    implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
 | 
			
		||||
    implementation(libs.indra)
 | 
			
		||||
    implementation(libs.shadow)
 | 
			
		||||
    implementation(libs.architectury.plugin)
 | 
			
		||||
    implementation(libs.architectury.loom)
 | 
			
		||||
    implementation(libs.minotaur)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								build-logic/settings.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								build-logic/settings.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
@file:Suppress("UnstableApiUsage")
 | 
			
		||||
 | 
			
		||||
dependencyResolutionManagement {
 | 
			
		||||
    versionCatalogs {
 | 
			
		||||
        create("libs") {
 | 
			
		||||
            from(files("../gradle/libs.versions.toml"))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rootProject.name = "build-logic"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,8 +22,8 @@ indra {
 | 
			
		|||
 | 
			
		||||
tasks {
 | 
			
		||||
    processResources {
 | 
			
		||||
        // Spigot, BungeeCord, Velocity, Fabric, ViaProxy
 | 
			
		||||
        filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml")) {
 | 
			
		||||
        // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge
 | 
			
		||||
        filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/mods.toml")) {
 | 
			
		||||
            expand(
 | 
			
		||||
                "id" to "geyser",
 | 
			
		||||
                "name" to "Geyser",
 | 
			
		||||
| 
						 | 
				
			
			@ -34,4 +34,4 @@ tasks {
 | 
			
		|||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,50 +1,22 @@
 | 
			
		|||
@file:Suppress("UnstableApiUsage")
 | 
			
		||||
 | 
			
		||||
import net.fabricmc.loom.task.RemapJarTask
 | 
			
		||||
import org.gradle.kotlin.dsl.dependencies
 | 
			
		||||
import org.gradle.kotlin.dsl.maven
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    id("fabric-loom") version "1.0-SNAPSHOT"
 | 
			
		||||
    id("com.modrinth.minotaur") version "2.+"
 | 
			
		||||
    id("geyser.publish-conventions")
 | 
			
		||||
    id("architectury-plugin")
 | 
			
		||||
    id("dev.architectury.loom")
 | 
			
		||||
    id("com.modrinth.minotaur")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    //to change the versions see the gradle.properties file
 | 
			
		||||
    minecraft(libs.fabric.minecraft)
 | 
			
		||||
    mappings(loom.officialMojangMappings())
 | 
			
		||||
    modImplementation(libs.fabric.loader)
 | 
			
		||||
 | 
			
		||||
    // Fabric API. This is technically optional, but you probably want it anyway.
 | 
			
		||||
    modImplementation(libs.fabric.api)
 | 
			
		||||
 | 
			
		||||
    // This should be in the libs TOML, but something about modImplementation AND include just doesn't work
 | 
			
		||||
    include(modImplementation("me.lucko", "fabric-permissions-api", "0.2-SNAPSHOT"))
 | 
			
		||||
 | 
			
		||||
    // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
 | 
			
		||||
    // You may need to force-disable transitiveness on them.
 | 
			
		||||
 | 
			
		||||
    api(projects.core)
 | 
			
		||||
    shadow(projects.core) {
 | 
			
		||||
        exclude(group = "com.google.guava", module = "guava")
 | 
			
		||||
        exclude(group = "com.google.code.gson", module = "gson")
 | 
			
		||||
        exclude(group = "org.slf4j")
 | 
			
		||||
        exclude(group = "com.nukkitx.fastutil")
 | 
			
		||||
        exclude(group = "io.netty.incubator")
 | 
			
		||||
    }
 | 
			
		||||
architectury {
 | 
			
		||||
    minecraft = "1.20.4"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
loom {
 | 
			
		||||
    mixin.defaultRefmapName.set("geyser-fabric-refmap.json")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    mavenLocal()
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-releases/")
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-snapshots/")
 | 
			
		||||
    maven("https://jitpack.io")
 | 
			
		||||
    maven("https://oss.sonatype.org/content/repositories/snapshots/")
 | 
			
		||||
    maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
application {
 | 
			
		||||
    mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
 | 
			
		||||
    silentMojangMappingsLicense()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks {
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +31,7 @@ tasks {
 | 
			
		|||
    shadowJar {
 | 
			
		||||
        // Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
 | 
			
		||||
        configurations = listOf(project.configurations.shadow.get())
 | 
			
		||||
        // The remapped shadowJar is the final desired Geyser-Fabric.jar
 | 
			
		||||
        // The remapped shadowJar is the final desired mod jar
 | 
			
		||||
        archiveVersion.set(project.version.toString())
 | 
			
		||||
        archiveClassifier.set("shaded")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,20 +61,32 @@ tasks {
 | 
			
		|||
    remapJar {
 | 
			
		||||
        dependsOn(shadowJar)
 | 
			
		||||
        inputFile.set(shadowJar.get().archiveFile)
 | 
			
		||||
        archiveBaseName.set("Geyser-Fabric")
 | 
			
		||||
        archiveVersion.set("")
 | 
			
		||||
        archiveClassifier.set("")
 | 
			
		||||
        archiveVersion.set("")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    register("remapModrinthJar", RemapJarTask::class) {
 | 
			
		||||
        dependsOn(shadowJar)
 | 
			
		||||
        inputFile.set(shadowJar.get().archiveFile)
 | 
			
		||||
        archiveBaseName.set("geyser-fabric")
 | 
			
		||||
        archiveVersion.set(project.version.toString() + "+build."  + System.getenv("GITHUB_RUN_NUMBER"))
 | 
			
		||||
        archiveClassifier.set("")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    minecraft("com.mojang:minecraft:1.20.4")
 | 
			
		||||
    mappings(loom.officialMojangMappings())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-releases/")
 | 
			
		||||
    maven("https://repo.opencollab.dev/maven-snapshots/")
 | 
			
		||||
    maven("https://jitpack.io")
 | 
			
		||||
    maven("https://oss.sonatype.org/content/repositories/snapshots/")
 | 
			
		||||
    maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
 | 
			
		||||
    maven("https://maven.neoforged.net/releases")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
modrinth {
 | 
			
		||||
    token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
 | 
			
		||||
    projectId.set("wKkoqHrH")
 | 
			
		||||
| 
						 | 
				
			
			@ -114,11 +98,5 @@ modrinth {
 | 
			
		|||
 | 
			
		||||
    uploadFile.set(tasks.getByPath("remapModrinthJar"))
 | 
			
		||||
    gameVersions.addAll("1.20.4")
 | 
			
		||||
 | 
			
		||||
    loaders.add("fabric")
 | 
			
		||||
    failSilently.set(true)
 | 
			
		||||
 | 
			
		||||
    dependencies {
 | 
			
		||||
        required.project("fabric-api")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
plugins {
 | 
			
		||||
    `java-library`
 | 
			
		||||
    // Ensure AP works in eclipse (no effect on other IDEs)
 | 
			
		||||
    `eclipse`
 | 
			
		||||
    eclipse
 | 
			
		||||
    id("geyser.build-logic")
 | 
			
		||||
    id("io.freefair.lombok") version "6.3.0" apply false
 | 
			
		||||
    alias(libs.plugins.lombok) apply false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
| 
						 | 
				
			
			@ -12,14 +12,7 @@ allprojects {
 | 
			
		|||
    description = properties["description"] as String
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    toolchain {
 | 
			
		||||
        languageVersion.set(JavaLanguageVersion.of(17))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val platforms = setOf(
 | 
			
		||||
    projects.fabric,
 | 
			
		||||
val basePlatforms = setOf(
 | 
			
		||||
    projects.bungeecord,
 | 
			
		||||
    projects.spigot,
 | 
			
		||||
    projects.standalone,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +20,12 @@ val platforms = setOf(
 | 
			
		|||
    projects.viaproxy
 | 
			
		||||
).map { it.dependencyProject }
 | 
			
		||||
 | 
			
		||||
val moddedPlatforms = setOf(
 | 
			
		||||
    projects.fabric,
 | 
			
		||||
    projects.neoforge,
 | 
			
		||||
    projects.mod
 | 
			
		||||
).map { it.dependencyProject }
 | 
			
		||||
 | 
			
		||||
subprojects {
 | 
			
		||||
    apply {
 | 
			
		||||
        plugin("java-library")
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +34,8 @@ subprojects {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    when (this) {
 | 
			
		||||
        in platforms -> plugins.apply("geyser.platform-conventions")
 | 
			
		||||
        in basePlatforms -> plugins.apply("geyser.platform-conventions")
 | 
			
		||||
        in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
 | 
			
		||||
        else -> plugins.apply("geyser.base-conventions")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
import net.kyori.blossom.BlossomExtension
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    id("net.kyori.blossom")
 | 
			
		||||
    id("net.kyori.indra.git")
 | 
			
		||||
    alias(libs.plugins.blossom)
 | 
			
		||||
    id("geyser.publish-conventions")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -221,6 +221,7 @@ public class GeyserImpl implements GeyserApi {
 | 
			
		|||
            if (ex != null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MinecraftLocale.ensureEN_US();
 | 
			
		||||
            String locale = GeyserLocale.getDefaultLocale();
 | 
			
		||||
            if (!"en_us".equals(locale)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ public class SkullResourcePackManager {
 | 
			
		|||
 | 
			
		||||
            ZipEntry entry = new ZipEntry("skull_resource_pack/pack_icon.png");
 | 
			
		||||
            zipOS.putNextEntry(entry);
 | 
			
		||||
            zipOS.write(FileUtils.readAllBytes("icon.png"));
 | 
			
		||||
            zipOS.write(FileUtils.readAllBytes("assets/geyser/icon.png"));
 | 
			
		||||
            zipOS.closeEntry();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,7 +123,8 @@ public class PendingMicrosoftAuthentication {
 | 
			
		|||
 | 
			
		||||
        public CompletableFuture<MsaAuthenticationService.MsCodeResponse> getCode(boolean offlineAccess) {
 | 
			
		||||
            // Request the code
 | 
			
		||||
            CompletableFuture<MsaAuthenticationService.MsCodeResponse> code = CompletableFuture.supplyAsync(() -> tryGetCode(offlineAccess));
 | 
			
		||||
            CompletableFuture<MsaAuthenticationService.MsCodeResponse> code = CompletableFuture.supplyAsync(
 | 
			
		||||
                    () -> tryGetCode(offlineAccess));
 | 
			
		||||
            // Once the code is received, continuously try to request the access token, profile, etc
 | 
			
		||||
            code.thenRun(() -> performLoginAttempt(System.currentTimeMillis()));
 | 
			
		||||
            return code;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 113 KiB  | 
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
# Gradle settings
 | 
			
		||||
org.gradle.jvmargs=-Xmx4G
 | 
			
		||||
org.gradle.configureondemand=true
 | 
			
		||||
org.gradle.caching=true
 | 
			
		||||
org.gradle.daemon=false
 | 
			
		||||
org.gradle.parallel=true
 | 
			
		||||
org.gradle.caching=true
 | 
			
		||||
org.gradle.vfs.watch=false
 | 
			
		||||
 | 
			
		||||
group=org.geysermc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,18 @@ viaproxy = "3.2.0-SNAPSHOT"
 | 
			
		|||
fabric-minecraft = "1.20.4"
 | 
			
		||||
fabric-loader = "0.15.2"
 | 
			
		||||
fabric-api = "0.91.2+1.20.4"
 | 
			
		||||
fabric-permissions = "0.2-SNAPSHOT"
 | 
			
		||||
neoforge-minecraft = "20.4.48-beta"
 | 
			
		||||
mixin = "0.8.5"
 | 
			
		||||
 | 
			
		||||
# plugin versions
 | 
			
		||||
indra = "3.1.3"
 | 
			
		||||
shadow = "7.1.3-SNAPSHOT"
 | 
			
		||||
architectury-plugin = "3.4-SNAPSHOT"
 | 
			
		||||
architectury-loom = "1.4-SNAPSHOT"
 | 
			
		||||
minotaur = "2.8.7"
 | 
			
		||||
lombok = "8.4"
 | 
			
		||||
blossom = "1.2.0"
 | 
			
		||||
 | 
			
		||||
[libraries]
 | 
			
		||||
base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base-api" }
 | 
			
		||||
| 
						 | 
				
			
			@ -75,10 +87,15 @@ jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jlin
 | 
			
		|||
folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" }
 | 
			
		||||
paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" }
 | 
			
		||||
 | 
			
		||||
# check these on https://modmuss50.me/fabric.html
 | 
			
		||||
mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" }
 | 
			
		||||
 | 
			
		||||
# Check these on https://modmuss50.me/fabric.html
 | 
			
		||||
fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" }
 | 
			
		||||
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
 | 
			
		||||
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
 | 
			
		||||
fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions" }
 | 
			
		||||
 | 
			
		||||
neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-minecraft" }
 | 
			
		||||
 | 
			
		||||
adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" }
 | 
			
		||||
bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" }
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +121,18 @@ math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" }
 | 
			
		|||
 | 
			
		||||
blockstateupdater = { group = "org.cloudburstmc", name = "block-state-updater", version.ref = "blockstateupdater"}
 | 
			
		||||
 | 
			
		||||
# plugins
 | 
			
		||||
indra = { group = "net.kyori", name  = "indra-common", version.ref = "indra" }
 | 
			
		||||
shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" }
 | 
			
		||||
architectury-plugin = { group = "architectury-plugin", name = "architectury-plugin.gradle.plugin", version.ref = "architectury-plugin" }
 | 
			
		||||
architectury-loom = { group = "dev.architectury.loom", name = "dev.architectury.loom.gradle.plugin", version.ref = "architectury-loom" }
 | 
			
		||||
minotaur = { group = "com.modrinth.minotaur", name = "Minotaur", version.ref = "minotaur" }
 | 
			
		||||
 | 
			
		||||
[plugins]
 | 
			
		||||
lombok = { id = "io.freefair.lombok", version.ref = "lombok" }
 | 
			
		||||
indra = { id = "net.kyori.indra", version.ref = "indra" }
 | 
			
		||||
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
 | 
			
		||||
 | 
			
		||||
[bundles]
 | 
			
		||||
jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ]
 | 
			
		||||
fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
@file:Suppress("UnstableApiUsage")
 | 
			
		||||
 | 
			
		||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
 | 
			
		||||
 | 
			
		||||
dependencyResolutionManagement {
 | 
			
		||||
//    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
 | 
			
		||||
    repositories {
 | 
			
		||||
        // Floodgate, Cumulus etc.
 | 
			
		||||
        maven("https://repo.opencollab.dev/main")
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,11 @@ dependencyResolutionManagement {
 | 
			
		|||
            mavenContent { snapshotsOnly() }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // NeoForge
 | 
			
		||||
        maven("https://maven.neoforged.net/releases") {
 | 
			
		||||
            mavenContent { releasesOnly() }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Minecraft
 | 
			
		||||
        maven("https://libraries.minecraft.net") {
 | 
			
		||||
            name = "minecraft"
 | 
			
		||||
| 
						 | 
				
			
			@ -44,13 +50,11 @@ dependencyResolutionManagement {
 | 
			
		|||
pluginManagement {
 | 
			
		||||
    repositories {
 | 
			
		||||
        gradlePluginPortal()
 | 
			
		||||
 | 
			
		||||
        maven("https://repo.opencollab.dev/maven-snapshots/")
 | 
			
		||||
        maven("https://maven.fabricmc.net/")
 | 
			
		||||
        maven("https://repo.opencollab.dev/maven-snapshots")
 | 
			
		||||
    }
 | 
			
		||||
    plugins {
 | 
			
		||||
        id("net.kyori.blossom") version "1.2.0"
 | 
			
		||||
        id("net.kyori.indra")
 | 
			
		||||
        id("net.kyori.indra.git")
 | 
			
		||||
        maven("https://maven.architectury.dev/")
 | 
			
		||||
        maven("https://maven.neoforged.net/releases")
 | 
			
		||||
    }
 | 
			
		||||
    includeBuild("build-logic")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +65,8 @@ include(":ap")
 | 
			
		|||
include(":api")
 | 
			
		||||
include(":bungeecord")
 | 
			
		||||
include(":fabric")
 | 
			
		||||
include(":neoforge")
 | 
			
		||||
include(":mod")
 | 
			
		||||
include(":spigot")
 | 
			
		||||
include(":standalone")
 | 
			
		||||
include(":velocity")
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +76,9 @@ include(":core")
 | 
			
		|||
 | 
			
		||||
// Specify project dirs
 | 
			
		||||
project(":bungeecord").projectDir = file("bootstrap/bungeecord")
 | 
			
		||||
project(":fabric").projectDir = file("bootstrap/fabric")
 | 
			
		||||
project(":fabric").projectDir = file("bootstrap/mod/fabric")
 | 
			
		||||
project(":neoforge").projectDir = file("bootstrap/mod/neoforge")
 | 
			
		||||
project(":mod").projectDir = file("bootstrap/mod")
 | 
			
		||||
project(":spigot").projectDir = file("bootstrap/spigot")
 | 
			
		||||
project(":standalone").projectDir = file("bootstrap/standalone")
 | 
			
		||||
project(":velocity").projectDir = file("bootstrap/velocity")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue