mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 14:34:59 +01: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()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
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
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
- name: Archive artifacts (Geyser Standalone)
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
|
@ -118,7 +125,7 @@ jobs:
|
||||||
echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
|
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/
|
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
|
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||||
env:
|
env:
|
||||||
|
@ -126,7 +133,16 @@ jobs:
|
||||||
with:
|
with:
|
||||||
arguments: fabric:modrinth
|
arguments: fabric:modrinth
|
||||||
gradle-home-cache-cleanup: true
|
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
|
- name: Notify Discord
|
||||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||||
# See https://github.com/Tim203/actions-git-discord-webhook/commits
|
# 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()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
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
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
- name: Archive artifacts (Geyser Standalone)
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
|
|
|
@ -42,4 +42,4 @@ public abstract class PathPackCodec extends PackCodec {
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public abstract Path path();
|
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 ANDROID = new PlatformType("Android");
|
||||||
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
|
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
|
||||||
public static final PlatformType FABRIC = new PlatformType("Fabric");
|
public static final PlatformType FABRIC = new PlatformType("Fabric");
|
||||||
|
public static final PlatformType NEOFORGE = new PlatformType("NeoForge");
|
||||||
public static final PlatformType SPIGOT = new PlatformType("Spigot");
|
public static final PlatformType SPIGOT = new PlatformType("Spigot");
|
||||||
|
|
||||||
@Deprecated
|
@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": {
|
"contact": {
|
||||||
"website": "${url}",
|
"website": "${url}",
|
||||||
"repo": "https://github.com/GeyserMC/Geyser-Fabric"
|
"repo": "https://github.com/GeyserMC/Geyser"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"icon": "assets/geyser-fabric/icon.png",
|
"icon": "assets/geyser/icon.png",
|
||||||
"environment": "*",
|
"environment": "*",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"main": [
|
"main": [
|
||||||
"org.geysermc.geyser.platform.fabric.GeyserFabricMod"
|
"org.geysermc.geyser.platform.fabric.GeyserFabricBootstrap"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"geyser-fabric.mixins.json"
|
"geyser.mixins.json"
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.15.2",
|
"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
|
* @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.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
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.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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.GeyserLogger;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
import org.geysermc.geyser.api.extension.Extension;
|
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.GeyserCommand;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
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.level.WorldManager;
|
||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
|
import org.geysermc.geyser.platform.mod.command.GeyserModCommandExecutor;
|
||||||
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
|
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.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.util.FileUtils;
|
||||||
|
|
||||||
|
@ -64,58 +60,46 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
@RequiredArgsConstructor
|
||||||
|
public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static GeyserFabricMod instance;
|
private static GeyserModBootstrap instance;
|
||||||
|
|
||||||
|
private final GeyserModPlatform platform;
|
||||||
|
|
||||||
private GeyserImpl geyser;
|
private GeyserImpl geyser;
|
||||||
private ModContainer mod;
|
|
||||||
private Path dataFolder;
|
private Path dataFolder;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private MinecraftServer server;
|
private MinecraftServer server;
|
||||||
|
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserFabricConfiguration geyserConfig;
|
private GeyserModConfiguration geyserConfig;
|
||||||
private GeyserFabricLogger geyserLogger;
|
private GeyserModInjector geyserInjector;
|
||||||
|
private GeyserModLogger geyserLogger;
|
||||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
private WorldManager geyserWorldManager;
|
private WorldManager geyserWorldManager;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitialize() {
|
|
||||||
instance = this;
|
|
||||||
mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
|
|
||||||
onGeyserInitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGeyserInitialize() {
|
public void onGeyserInitialize() {
|
||||||
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
|
instance = this;
|
||||||
// Set as an event, so we can get the proper IP and port if needed
|
dataFolder = this.platform.dataFolder(this.platform.configPath());
|
||||||
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");
|
|
||||||
GeyserLocale.init(this);
|
GeyserLocale.init(this);
|
||||||
if (!loadConfig()) {
|
if (!loadConfig()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserModLogger(geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
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() {
|
public void onGeyserEnable() {
|
||||||
if (GeyserImpl.getInstance().isReloading()) {
|
if (GeyserImpl.getInstance().isReloading()) {
|
||||||
if (!loadConfig()) {
|
if (!loadConfig()) {
|
||||||
|
@ -123,35 +107,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
}
|
}
|
||||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
} else {
|
|
||||||
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
|
||||||
this.geyserCommandManager.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeyserImpl.start();
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
} else {
|
} else {
|
||||||
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
|
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeyserImpl.start();
|
// No need to re-register commands, or try to re-inject
|
||||||
|
|
||||||
// No need to re-register commands, or re-recreate the world manager when reloading
|
|
||||||
if (GeyserImpl.getInstance().isReloading()) {
|
if (GeyserImpl.getInstance().isReloading()) {
|
||||||
return;
|
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
|
// Start command building
|
||||||
// Set just "geyser" as the help command
|
// Set just "geyser" as the help command
|
||||||
GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
|
GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(geyser,
|
||||||
(GeyserCommand) geyser.commandManager().getCommands().get("help"));
|
(GeyserCommand) geyser.commandManager().getCommands().get("help"));
|
||||||
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
|
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
|
||||||
|
|
||||||
// Register all subcommands as valid
|
// Register all subcommands as valid
|
||||||
for (Map.Entry<String, Command> command : geyser.commandManager().getCommands().entrySet()) {
|
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())
|
builder.then(Commands.literal(command.getKey())
|
||||||
.executes(executor)
|
.executes(executor)
|
||||||
// Could also test for Bedrock but depending on when this is called it may backfire
|
// 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>"
|
// Register help command for just "/<extensionId>"
|
||||||
GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
|
GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(geyser,
|
||||||
(GeyserCommand) extensionCommands.get("help"));
|
(GeyserCommand) extensionCommands.get("help"));
|
||||||
LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
|
LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
|
||||||
|
|
||||||
for (Map.Entry<String, Command> command : extensionCommands.entrySet()) {
|
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())
|
extCmdBuilder.then(Commands.literal(command.getKey())
|
||||||
.executes(executor)
|
.executes(executor)
|
||||||
.requires(executor::testPermission)
|
.requires(executor::testPermission)
|
||||||
|
@ -201,11 +187,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
geyser.shutdown();
|
geyser.shutdown();
|
||||||
geyser = null;
|
geyser = null;
|
||||||
}
|
}
|
||||||
this.server = null;
|
if (geyserInjector != null) {
|
||||||
|
geyserInjector.shutdown();
|
||||||
|
this.server = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserConfiguration getGeyserConfig() {
|
public GeyserModConfiguration getGeyserConfig() {
|
||||||
return geyserConfig;
|
return geyserConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +225,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BootstrapDumpInfo getDumpInfo() {
|
public BootstrapDumpInfo getDumpInfo() {
|
||||||
return new GeyserFabricDumpInfo(server);
|
return this.platform.dumpInfo(this.server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -258,32 +247,19 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testFloodgatePluginPresent() {
|
public boolean testFloodgatePluginPresent() {
|
||||||
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
return this.platform.testFloodgatePluginPresent(this);
|
||||||
if (floodgate.isPresent()) {
|
|
||||||
geyserConfig.loadFloodgate(this, floodgate.orElse(null));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public InputStream getResourceOrNull(String resource) {
|
public InputStream getResourceOrNull(String resource) {
|
||||||
// We need to handle this differently, because Fabric shares the classloader across multiple mods
|
return this.platform.resolveResource(resource);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode);
|
||||||
|
|
||||||
|
public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel);
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
private boolean loadConfig() {
|
private boolean loadConfig() {
|
||||||
try {
|
try {
|
||||||
|
@ -294,10 +270,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
|
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
|
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
|
||||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException ex) {
|
} 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();
|
ex.printStackTrace();
|
||||||
return false;
|
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
|
* @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 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.FloodgateKeyLoader;
|
||||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public class GeyserFabricConfiguration extends GeyserJacksonConfiguration {
|
public class GeyserModConfiguration extends GeyserJacksonConfiguration {
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Path floodgateKeyPath;
|
private Path floodgateKeyPath;
|
||||||
|
|
||||||
public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) {
|
public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
|
||||||
Path geyserDataFolder = geyser.getConfigFolder();
|
Path geyserDataFolder = geyser.getConfigFolder();
|
||||||
Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
|
|
||||||
|
|
||||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
|
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
|
* @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.Component;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
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.GeyserLogger;
|
||||||
import org.geysermc.geyser.text.ChatColor;
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
|
|
||||||
public class GeyserFabricLogger implements GeyserLogger {
|
public class GeyserModLogger implements GeyserLogger {
|
||||||
private final Logger logger = LogManager.getLogger("geyser-fabric");
|
private final Logger logger = LogManager.getLogger("geyser");
|
||||||
|
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
|
|
||||||
public GeyserFabricLogger(boolean isDebug) {
|
public GeyserModLogger(boolean isDebug) {
|
||||||
debug = isDebug;
|
debug = isDebug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class GeyserFabricLogger implements GeyserLogger {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Component message) {
|
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);
|
String flattened = LegacyComponentSerializer.legacySection().serialize(message);
|
||||||
// Add the reset at the end, or else format will persist... forever.
|
// Add the reset at the end, or else format will persist... forever.
|
||||||
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
|
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
|
|
@ -23,21 +23,22 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.commands.CommandSourceStack;
|
||||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import org.geysermc.geyser.Constants;
|
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;
|
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||||
|
|
||||||
public final class GeyserFabricUpdateListener {
|
public final class GeyserModUpdateListener {
|
||||||
public static void onPlayReady(ServerGamePacketListenerImpl handler) {
|
public static void onPlayReady(Player player) {
|
||||||
if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) {
|
CommandSourceStack stack = player.createCommandSourceStack();
|
||||||
VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.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
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.fabric;
|
package org.geysermc.geyser.platform.mod;
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.fabric;
|
package org.geysermc.geyser.platform.mod;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import net.kyori.adventure.text.Component;
|
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.network.protocol.status.ServerboundStatusRequestPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
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.GeyserLogger;
|
||||||
import org.geysermc.geyser.ping.GeyserPingInfo;
|
import org.geysermc.geyser.ping.GeyserPingInfo;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -100,7 +101,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
if (packet instanceof ClientboundStatusResponsePacket statusResponse) {
|
||||||
status = statusResponse.status();
|
status = statusResponse.status();
|
||||||
}
|
}
|
|
@ -23,31 +23,31 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.Command;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
||||||
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.ChatColor;
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
|
public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
|
||||||
private final GeyserCommand command;
|
private final GeyserCommand command;
|
||||||
|
|
||||||
public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
|
public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) {
|
||||||
super(connector, Collections.singletonMap(command.name(), command));
|
super(geyser, Collections.singletonMap(command.name(), command));
|
||||||
this.command = command;
|
this.command = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean testPermission(CommandSourceStack source) {
|
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
|
@Override
|
||||||
|
@ -57,7 +57,7 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
|
||||||
|
|
||||||
public int runWithArgs(CommandContext<CommandSourceStack> context, String args) {
|
public int runWithArgs(CommandContext<CommandSourceStack> context, String args) {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
FabricCommandSender sender = new FabricCommandSender(source);
|
ModCommandSender sender = new ModCommandSender(source);
|
||||||
GeyserSession session = getGeyserSession(sender);
|
GeyserSession session = getGeyserSession(sender);
|
||||||
if (!testPermission(source)) {
|
if (!testPermission(source)) {
|
||||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
|
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
|
|
@ -23,9 +23,8 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.network.chat.Component;
|
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.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.text.ChatColor;
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class FabricCommandSender implements GeyserCommandSource {
|
public class ModCommandSender implements GeyserCommandSource {
|
||||||
|
|
||||||
private final CommandSourceStack source;
|
private final CommandSourceStack source;
|
||||||
|
|
||||||
public FabricCommandSender(CommandSourceStack source) {
|
public ModCommandSender(CommandSourceStack source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,6 @@ public class FabricCommandSender implements GeyserCommandSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(String permission) {
|
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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -23,18 +23,16 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.Minecraft;
|
||||||
import net.minecraft.client.server.IntegratedServer;
|
import net.minecraft.client.server.IntegratedServer;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.level.GameType;
|
import net.minecraft.world.level.GameType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
|
import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
@ -45,7 +43,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
|
||||||
@Mixin(IntegratedServer.class)
|
@Mixin(IntegratedServer.class)
|
||||||
public class IntegratedServerMixin implements GeyserServerPortGetter {
|
public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||||
@Shadow
|
@Shadow
|
||||||
|
@ -57,8 +54,8 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||||
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
||||||
if (cir.getReturnValueZ()) {
|
if (cir.getReturnValueZ()) {
|
||||||
// If the LAN is opened, starts Geyser.
|
// If the LAN is opened, starts Geyser.
|
||||||
GeyserFabricMod.getInstance().setServer((MinecraftServer) (Object) this);
|
GeyserModBootstrap.getInstance().setServer((MinecraftServer) (Object) this);
|
||||||
GeyserFabricMod.getInstance().onGeyserEnable();
|
GeyserModBootstrap.getInstance().onGeyserEnable();
|
||||||
// Ensure player locale has been loaded, in case it's different from Java system language
|
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||||
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||||
// Give indication that Geyser is loaded
|
// 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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 com.mojang.datafixers.DataFixer;
|
||||||
import net.minecraft.server.MinecraftServer;
|
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.level.progress.ChunkProgressListenerFactory;
|
||||||
import net.minecraft.server.packs.repository.PackRepository;
|
import net.minecraft.server.packs.repository.PackRepository;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
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 org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
|
|
||||||
@Mixin(DedicatedServer.class)
|
@Mixin(DedicatedServer.class)
|
||||||
public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
|
public abstract class DedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
|
||||||
public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
|
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);
|
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
|
* @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.entity.player.GameMode;
|
||||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
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.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.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.WritableBookItem;
|
import net.minecraft.world.item.WritableBookItem;
|
||||||
import net.minecraft.world.item.WrittenBookItem;
|
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.BannerBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
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.LevelChunk;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
|
@ -46,6 +65,8 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.geysermc.erosion.util.LecternUtils;
|
import org.geysermc.erosion.util.LecternUtils;
|
||||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||||
|
|
||||||
|
@ -54,13 +75,54 @@ import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class GeyserFabricWorldManager extends GeyserWorldManager {
|
public class GeyserModWorldManager extends GeyserWorldManager {
|
||||||
private final MinecraftServer server;
|
private final MinecraftServer server;
|
||||||
|
|
||||||
public GeyserFabricWorldManager(MinecraftServer server) {
|
public GeyserModWorldManager(MinecraftServer server) {
|
||||||
this.server = 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
|
@Override
|
||||||
public boolean shouldExpectLecternHandled(GeyserSession session) {
|
public boolean shouldExpectLecternHandled(GeyserSession session) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -154,7 +216,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(GeyserSession session, String permission) {
|
public boolean hasPermission(GeyserSession session, String permission) {
|
||||||
ServerPlayer player = getPlayer(session);
|
ServerPlayer player = getPlayer(session);
|
||||||
return Permissions.check(player, permission);
|
return GeyserModBootstrap.getInstance().hasPermission(player, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
Container cp = frame.getContentPane();
|
||||||
|
|
||||||
// Fetch and set the icon for the frame
|
// 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) {
|
if (image != null) {
|
||||||
ImageIcon icon = new ImageIcon(image);
|
ImageIcon icon = new ImageIcon(image);
|
||||||
frame.setIconImage(icon.getImage());
|
frame.setIconImage(icon.getImage());
|
||||||
|
|
|
@ -4,14 +4,17 @@ plugins {
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
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 {
|
dependencies {
|
||||||
implementation("net.kyori", "indra-common", "3.1.1")
|
implementation(libs.indra)
|
||||||
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
|
implementation(libs.shadow)
|
||||||
|
implementation(libs.architectury.plugin)
|
||||||
// Within the gradle plugin classpath, there is a version conflict between loom and some other
|
implementation(libs.architectury.loom)
|
||||||
// plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
|
implementation(libs.minotaur)
|
||||||
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
|
|
||||||
}
|
}
|
||||||
|
|
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 {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
// Spigot, BungeeCord, Velocity, Fabric, ViaProxy
|
// Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge
|
||||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml")) {
|
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/mods.toml")) {
|
||||||
expand(
|
expand(
|
||||||
"id" to "geyser",
|
"id" to "geyser",
|
||||||
"name" to "Geyser",
|
"name" to "Geyser",
|
||||||
|
@ -34,4 +34,4 @@ tasks {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,50 +1,22 @@
|
||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
import net.fabricmc.loom.task.RemapJarTask
|
import net.fabricmc.loom.task.RemapJarTask
|
||||||
|
import org.gradle.kotlin.dsl.dependencies
|
||||||
|
import org.gradle.kotlin.dsl.maven
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("fabric-loom") version "1.0-SNAPSHOT"
|
id("geyser.publish-conventions")
|
||||||
id("com.modrinth.minotaur") version "2.+"
|
id("architectury-plugin")
|
||||||
|
id("dev.architectury.loom")
|
||||||
|
id("com.modrinth.minotaur")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
architectury {
|
||||||
//to change the versions see the gradle.properties file
|
minecraft = "1.20.4"
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
mixin.defaultRefmapName.set("geyser-fabric-refmap.json")
|
silentMojangMappingsLicense()
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
@ -59,7 +31,7 @@ tasks {
|
||||||
shadowJar {
|
shadowJar {
|
||||||
// Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
|
// Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
|
||||||
configurations = listOf(project.configurations.shadow.get())
|
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())
|
archiveVersion.set(project.version.toString())
|
||||||
archiveClassifier.set("shaded")
|
archiveClassifier.set("shaded")
|
||||||
|
|
||||||
|
@ -89,20 +61,32 @@ tasks {
|
||||||
remapJar {
|
remapJar {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
inputFile.set(shadowJar.get().archiveFile)
|
inputFile.set(shadowJar.get().archiveFile)
|
||||||
archiveBaseName.set("Geyser-Fabric")
|
|
||||||
archiveVersion.set("")
|
|
||||||
archiveClassifier.set("")
|
archiveClassifier.set("")
|
||||||
|
archiveVersion.set("")
|
||||||
}
|
}
|
||||||
|
|
||||||
register("remapModrinthJar", RemapJarTask::class) {
|
register("remapModrinthJar", RemapJarTask::class) {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
inputFile.set(shadowJar.get().archiveFile)
|
inputFile.set(shadowJar.get().archiveFile)
|
||||||
archiveBaseName.set("geyser-fabric")
|
|
||||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
|
archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
|
||||||
archiveClassifier.set("")
|
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 {
|
modrinth {
|
||||||
token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||||
projectId.set("wKkoqHrH")
|
projectId.set("wKkoqHrH")
|
||||||
|
@ -114,11 +98,5 @@ modrinth {
|
||||||
|
|
||||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||||
gameVersions.addAll("1.20.4")
|
gameVersions.addAll("1.20.4")
|
||||||
|
|
||||||
loaders.add("fabric")
|
|
||||||
failSilently.set(true)
|
failSilently.set(true)
|
||||||
|
}
|
||||||
dependencies {
|
|
||||||
required.project("fabric-api")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
// Ensure AP works in eclipse (no effect on other IDEs)
|
// Ensure AP works in eclipse (no effect on other IDEs)
|
||||||
`eclipse`
|
eclipse
|
||||||
id("geyser.build-logic")
|
id("geyser.build-logic")
|
||||||
id("io.freefair.lombok") version "6.3.0" apply false
|
alias(libs.plugins.lombok) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
@ -12,14 +12,7 @@ allprojects {
|
||||||
description = properties["description"] as String
|
description = properties["description"] as String
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
val basePlatforms = setOf(
|
||||||
toolchain {
|
|
||||||
languageVersion.set(JavaLanguageVersion.of(17))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val platforms = setOf(
|
|
||||||
projects.fabric,
|
|
||||||
projects.bungeecord,
|
projects.bungeecord,
|
||||||
projects.spigot,
|
projects.spigot,
|
||||||
projects.standalone,
|
projects.standalone,
|
||||||
|
@ -27,6 +20,12 @@ val platforms = setOf(
|
||||||
projects.viaproxy
|
projects.viaproxy
|
||||||
).map { it.dependencyProject }
|
).map { it.dependencyProject }
|
||||||
|
|
||||||
|
val moddedPlatforms = setOf(
|
||||||
|
projects.fabric,
|
||||||
|
projects.neoforge,
|
||||||
|
projects.mod
|
||||||
|
).map { it.dependencyProject }
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply {
|
apply {
|
||||||
plugin("java-library")
|
plugin("java-library")
|
||||||
|
@ -35,7 +34,8 @@ subprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
when (this) {
|
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")
|
else -> plugins.apply("geyser.base-conventions")
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
import net.kyori.blossom.BlossomExtension
|
import net.kyori.blossom.BlossomExtension
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("net.kyori.blossom")
|
alias(libs.plugins.blossom)
|
||||||
id("net.kyori.indra.git")
|
|
||||||
id("geyser.publish-conventions")
|
id("geyser.publish-conventions")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftLocale.ensureEN_US();
|
MinecraftLocale.ensureEN_US();
|
||||||
String locale = GeyserLocale.getDefaultLocale();
|
String locale = GeyserLocale.getDefaultLocale();
|
||||||
if (!"en_us".equals(locale)) {
|
if (!"en_us".equals(locale)) {
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class SkullResourcePackManager {
|
||||||
|
|
||||||
ZipEntry entry = new ZipEntry("skull_resource_pack/pack_icon.png");
|
ZipEntry entry = new ZipEntry("skull_resource_pack/pack_icon.png");
|
||||||
zipOS.putNextEntry(entry);
|
zipOS.putNextEntry(entry);
|
||||||
zipOS.write(FileUtils.readAllBytes("icon.png"));
|
zipOS.write(FileUtils.readAllBytes("assets/geyser/icon.png"));
|
||||||
zipOS.closeEntry();
|
zipOS.closeEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,8 @@ public class PendingMicrosoftAuthentication {
|
||||||
|
|
||||||
public CompletableFuture<MsaAuthenticationService.MsCodeResponse> getCode(boolean offlineAccess) {
|
public CompletableFuture<MsaAuthenticationService.MsCodeResponse> getCode(boolean offlineAccess) {
|
||||||
// Request the code
|
// 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
|
// Once the code is received, continuously try to request the access token, profile, etc
|
||||||
code.thenRun(() -> performLoginAttempt(System.currentTimeMillis()));
|
code.thenRun(() -> performLoginAttempt(System.currentTimeMillis()));
|
||||||
return code;
|
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
|
# Gradle settings
|
||||||
org.gradle.jvmargs=-Xmx4G
|
org.gradle.jvmargs=-Xmx4G
|
||||||
org.gradle.configureondemand=true
|
org.gradle.daemon=false
|
||||||
org.gradle.caching=true
|
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
org.gradle.vfs.watch=false
|
org.gradle.vfs.watch=false
|
||||||
|
|
||||||
group=org.geysermc
|
group=org.geysermc
|
||||||
|
|
|
@ -32,6 +32,18 @@ viaproxy = "3.2.0-SNAPSHOT"
|
||||||
fabric-minecraft = "1.20.4"
|
fabric-minecraft = "1.20.4"
|
||||||
fabric-loader = "0.15.2"
|
fabric-loader = "0.15.2"
|
||||||
fabric-api = "0.91.2+1.20.4"
|
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]
|
[libraries]
|
||||||
base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base-api" }
|
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" }
|
folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" }
|
||||||
paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", 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-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" }
|
||||||
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
|
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-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" }
|
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" }
|
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"}
|
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]
|
[bundles]
|
||||||
jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ]
|
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" ]
|
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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
|
||||||
repositories {
|
repositories {
|
||||||
// Floodgate, Cumulus etc.
|
// Floodgate, Cumulus etc.
|
||||||
maven("https://repo.opencollab.dev/main")
|
maven("https://repo.opencollab.dev/main")
|
||||||
|
@ -18,6 +19,11 @@ dependencyResolutionManagement {
|
||||||
mavenContent { snapshotsOnly() }
|
mavenContent { snapshotsOnly() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NeoForge
|
||||||
|
maven("https://maven.neoforged.net/releases") {
|
||||||
|
mavenContent { releasesOnly() }
|
||||||
|
}
|
||||||
|
|
||||||
// Minecraft
|
// Minecraft
|
||||||
maven("https://libraries.minecraft.net") {
|
maven("https://libraries.minecraft.net") {
|
||||||
name = "minecraft"
|
name = "minecraft"
|
||||||
|
@ -44,13 +50,11 @@ dependencyResolutionManagement {
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|
||||||
|
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||||
maven("https://maven.fabricmc.net/")
|
maven("https://maven.fabricmc.net/")
|
||||||
maven("https://repo.opencollab.dev/maven-snapshots")
|
maven("https://maven.architectury.dev/")
|
||||||
}
|
maven("https://maven.neoforged.net/releases")
|
||||||
plugins {
|
|
||||||
id("net.kyori.blossom") version "1.2.0"
|
|
||||||
id("net.kyori.indra")
|
|
||||||
id("net.kyori.indra.git")
|
|
||||||
}
|
}
|
||||||
includeBuild("build-logic")
|
includeBuild("build-logic")
|
||||||
}
|
}
|
||||||
|
@ -61,6 +65,8 @@ include(":ap")
|
||||||
include(":api")
|
include(":api")
|
||||||
include(":bungeecord")
|
include(":bungeecord")
|
||||||
include(":fabric")
|
include(":fabric")
|
||||||
|
include(":neoforge")
|
||||||
|
include(":mod")
|
||||||
include(":spigot")
|
include(":spigot")
|
||||||
include(":standalone")
|
include(":standalone")
|
||||||
include(":velocity")
|
include(":velocity")
|
||||||
|
@ -70,7 +76,9 @@ include(":core")
|
||||||
|
|
||||||
// Specify project dirs
|
// Specify project dirs
|
||||||
project(":bungeecord").projectDir = file("bootstrap/bungeecord")
|
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(":spigot").projectDir = file("bootstrap/spigot")
|
||||||
project(":standalone").projectDir = file("bootstrap/standalone")
|
project(":standalone").projectDir = file("bootstrap/standalone")
|
||||||
project(":velocity").projectDir = file("bootstrap/velocity")
|
project(":velocity").projectDir = file("bootstrap/velocity")
|
||||||
|
|
Loading…
Reference in a new issue