From 754c2f3d783ad74082cfd7942492d7e33d7b170f Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 12:15:07 -0400 Subject: [PATCH 001/100] First commit. --- bootstrap/fabric/.idea/copyright/Geyser.xml | 6 + .../.idea/copyright/profiles_settings.xml | 7 + bootstrap/fabric/LICENSE | 21 ++ bootstrap/fabric/build.gradle | 97 +++++++++ bootstrap/fabric/gradle.properties | 14 ++ .../gradle/wrapper/gradle-wrapper.properties | 5 + bootstrap/fabric/gradlew | 185 ++++++++++++++++++ bootstrap/fabric/gradlew.bat | 104 ++++++++++ bootstrap/fabric/settings.gradle | 10 + .../fabric/GeyserFabricConfiguration.java | 37 ++++ .../platform/fabric/GeyserFabricDumpInfo.java | 31 +++ .../platform/fabric/GeyserFabricLogger.java | 84 ++++++++ .../platform/fabric/GeyserFabricMod.java | 138 +++++++++++++ .../command/GeyserFabricCommandManager.java | 41 ++++ .../src/main/resources/fabric.mixins.json | 13 ++ .../fabric/src/main/resources/fabric.mod.json | 30 +++ 16 files changed, 823 insertions(+) create mode 100644 bootstrap/fabric/.idea/copyright/Geyser.xml create mode 100644 bootstrap/fabric/.idea/copyright/profiles_settings.xml create mode 100644 bootstrap/fabric/LICENSE create mode 100644 bootstrap/fabric/build.gradle create mode 100644 bootstrap/fabric/gradle.properties create mode 100644 bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties create mode 100755 bootstrap/fabric/gradlew create mode 100644 bootstrap/fabric/gradlew.bat create mode 100644 bootstrap/fabric/settings.gradle create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java create mode 100644 bootstrap/fabric/src/main/resources/fabric.mixins.json create mode 100644 bootstrap/fabric/src/main/resources/fabric.mod.json diff --git a/bootstrap/fabric/.idea/copyright/Geyser.xml b/bootstrap/fabric/.idea/copyright/Geyser.xml new file mode 100644 index 000000000..bdffbbbd6 --- /dev/null +++ b/bootstrap/fabric/.idea/copyright/Geyser.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/bootstrap/fabric/.idea/copyright/profiles_settings.xml b/bootstrap/fabric/.idea/copyright/profiles_settings.xml new file mode 100644 index 000000000..f2d5911c9 --- /dev/null +++ b/bootstrap/fabric/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/bootstrap/fabric/LICENSE b/bootstrap/fabric/LICENSE new file mode 100644 index 000000000..d8ee99620 --- /dev/null +++ b/bootstrap/fabric/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 GeyserMC + +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. diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle new file mode 100644 index 000000000..8377dab43 --- /dev/null +++ b/bootstrap/fabric/build.gradle @@ -0,0 +1,97 @@ +plugins { + id 'fabric-loom' version '0.5-SNAPSHOT' + id 'maven-publish' +} + +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 + +archivesBaseName = project.archives_base_name +version = project.mod_version +group = project.maven_group + +dependencies { + //to change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. + // You may need to force-disable transitiveness on them. + + implementation 'org.geysermc:connector:1.1.0' +} + +repositories { + maven { + url = uri('https://repo.nukkitx.com/maven-releases/') + } + + maven { + url = uri('https://repo.nukkitx.com/maven-snapshots/') + } + + maven { + url = uri('https://jitpack.io') + } + + maven { + url = uri('https://oss.sonatype.org/content/repositories/snapshots/') + } +} + +processResources { + inputs.property "version", project.version + + from(sourceSets.main.resources.srcDirs) { + include "fabric.mod.json" + expand "version": project.version + } + + from(sourceSets.main.resources.srcDirs) { + exclude "fabric.mod.json" + } +} + +// ensure that the encoding is set to UTF-8, no matter what the system default is +// this fixes some edge cases with special characters not displaying correctly +// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html +tasks.withType(JavaCompile) { + options.encoding = "UTF-8" +} + +// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task +// if it is present. +// If you remove this task, sources will not be generated. +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = "sources" + from sourceSets.main.allSource +} + +jar { + from "LICENSE" +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + // add all the jars that should be included when publishing to maven + artifact(remapJar) { + builtBy remapJar + } + artifact(sourcesJar) { + builtBy remapSourcesJar + } + } + } + + // select the repositories you want to publish to + repositories { + // uncomment to publish to the local maven + mavenLocal() + } +} diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties new file mode 100644 index 000000000..fbcb2816c --- /dev/null +++ b/bootstrap/fabric/gradle.properties @@ -0,0 +1,14 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version=1.16.3 +yarn_mappings=1.16.3+build.28 +loader_version=0.10.1+build.209 +# Mod Properties +mod_version=1.0-SNAPSHOT +maven_group=org.geysermc.platform +archives_base_name=fabric +# Dependencies +# check this on https://modmuss50.me/fabric.html +fabric_version=0.23.0+build.410-1.16 diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..bb8b2fc26 --- /dev/null +++ b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/bootstrap/fabric/gradlew b/bootstrap/fabric/gradlew new file mode 100755 index 000000000..fbd7c5158 --- /dev/null +++ b/bootstrap/fabric/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/bootstrap/fabric/gradlew.bat b/bootstrap/fabric/gradlew.bat new file mode 100644 index 000000000..a9f778a7a --- /dev/null +++ b/bootstrap/fabric/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/bootstrap/fabric/settings.gradle b/bootstrap/fabric/settings.gradle new file mode 100644 index 000000000..5b60df3d2 --- /dev/null +++ b/bootstrap/fabric/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + jcenter() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java new file mode 100644 index 000000000..9f843693a --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import org.geysermc.connector.configuration.GeyserJacksonConfiguration; + +import java.nio.file.Path; + +public class GeyserFabricConfiguration extends GeyserJacksonConfiguration { + @Override + public Path getFloodgateKeyPath() { + return null; + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java new file mode 100644 index 000000000..cd35e77f2 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import org.geysermc.connector.dump.BootstrapDumpInfo; + +public class GeyserFabricDumpInfo extends BootstrapDumpInfo { +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java new file mode 100644 index 000000000..c3f151c4c --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import org.geysermc.connector.GeyserLogger; + +public class GeyserFabricLogger implements GeyserLogger { + + private boolean debug; + + public GeyserFabricLogger(boolean isDebug) { + debug = isDebug; + } + + @Override + public void severe(String message) { + System.out.println(message); + } + + @Override + public void severe(String message, Throwable error) { + System.out.println(message); + } + + @Override + public void error(String message) { + System.out.println(message); + } + + @Override + public void error(String message, Throwable error) { + System.out.println(message); + } + + @Override + public void warning(String message) { + System.out.println(message); + } + + @Override + public void info(String message) { + System.out.println(message); + } + + @Override + public void debug(String message) { + if (debug) { + info(message); + } + } + + @Override + public void setDebug(boolean debug) { + this.debug = debug; + } + + @Override + public boolean isDebug() { + return debug; + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java new file mode 100644 index 000000000..fda3eb9ad --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import net.fabricmc.api.DedicatedServerModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.dedicated.DedicatedServer; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.GeyserLogger; +import org.geysermc.connector.bootstrap.GeyserBootstrap; +import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.common.PlatformType; +import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.dump.BootstrapDumpInfo; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; +import org.geysermc.connector.utils.FileUtils; +import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.UUID; + +@Environment(EnvType.SERVER) +public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBootstrap { + + private GeyserConnector connector; + private Path dataFolder; + + private GeyserFabricCommandManager geyserCommandManager; + private GeyserFabricConfiguration geyserConfig; + private GeyserFabricLogger geyserLogger; + private IGeyserPingPassthrough geyserPingPassthrough; + + @Override + public void onInitializeServer() { + this.onEnable(); + } + + @Override + public void onEnable() { + dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric"); + if (!dataFolder.toFile().exists()) { + //noinspection ResultOfMethodCallIgnored + dataFolder.toFile().mkdir(); + } + try { + File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", + (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); + this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); + } catch (IOException ex) { + System.out.println(LanguageUtils.getLocaleStringLog("geyser.config.failed")); + ex.printStackTrace(); + } + + this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode()); + + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + + if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { + this.geyserConfig.setAutoconfiguredRemote(true); + } + + if (geyserConfig.getBedrock().isCloneRemotePort()) { + geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + } + + this.connector = GeyserConnector.start(PlatformType.ANDROID, this); + + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + + this.geyserCommandManager = new GeyserFabricCommandManager(connector); + } + + @Override + public void onDisable() { + if (connector != null) { + connector.shutdown(); + } + } + + @Override + public GeyserConfiguration getGeyserConfig() { + return geyserConfig; + } + + @Override + public GeyserLogger getGeyserLogger() { + return geyserLogger; + } + + @Override + public CommandManager getGeyserCommandManager() { + return geyserCommandManager; + } + + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserPingPassthrough; + } + + @Override + public Path getConfigFolder() { + return dataFolder; + } + + @Override + public BootstrapDumpInfo getDumpInfo() { + return new GeyserFabricDumpInfo(); + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java new file mode 100644 index 000000000..d6180e7ec --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.command; + +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandManager; + +public class GeyserFabricCommandManager extends CommandManager { + + public GeyserFabricCommandManager(GeyserConnector connector) { + super(connector); + } + + @Override + public String getDescription(String command) { + return ""; + } +} diff --git a/bootstrap/fabric/src/main/resources/fabric.mixins.json b/bootstrap/fabric/src/main/resources/fabric.mixins.json new file mode 100644 index 000000000..a1f71d182 --- /dev/null +++ b/bootstrap/fabric/src/main/resources/fabric.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "org.geysermc.platform.fabric.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..10defc82d --- /dev/null +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "id": "geyser-fabric", + "version": "${version}", + "name": "Geyser-Fabric", + "description": "A bridge/proxy allowing you to connect to Minecraft: Java Edition servers with Minecraft: Bedrock Edition. ", + "authors": [ + "GeyserMC" + ], + "contact": { + "website": "https://geysermc.org", + "repo": "https://github.com/GeyserMC/Geyser-Fabric" + }, + "license": "MIT", + "icon": "assets/fabric/icon.png", + "environment": "server", + "entrypoints": { + "server": [ + "org.geysermc.platform.fabric.GeyserFabricMod" + ] + }, + "mixins": [ + "fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=0.10.1+build.209", + "fabric": "*", + "minecraft": "1.16.3" + } +} From e7c00d897f9a6bb66399e4dbc356a69f6d464f41 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 12:34:25 -0400 Subject: [PATCH 002/100] Add .gitignore --- bootstrap/fabric/.gitignore | 239 ++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 bootstrap/fabric/.gitignore diff --git a/bootstrap/fabric/.gitignore b/bootstrap/fabric/.gitignore new file mode 100644 index 000000000..4215ddd83 --- /dev/null +++ b/bootstrap/fabric/.gitignore @@ -0,0 +1,239 @@ + +# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode +# Edit at https://www.gitignore.io/gitignore?templates=git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +.project + +### Eclipse Patch ### +# Spring Boot Tooling +.sts4-cache/ + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +### NetBeans ### +**/nbproject/private/ +**/nbproject/Makefile-*.mk +**/nbproject/Package-*.bash +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +### VisualStudioCode ### +# Note: Manually edited to remove settings files +.vscode/* +# !.vscode/settings.json +# !.vscode/tasks.json +# !.vscode/launch.json +# !.vscode/extensions.json +# *.code-workspace + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode + +### Geyser ### +run/ From be07a47f9fad0e3e41bb99e2d02714a9be407997 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 13:41:50 -0400 Subject: [PATCH 003/100] Implement proper logger, shutdown, and IP checking --- .../platform/fabric/GeyserFabricLogger.java | 18 +++++++++++------- .../platform/fabric/GeyserFabricMod.java | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java index c3f151c4c..40e18e43b 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java @@ -25,10 +25,14 @@ package org.geysermc.platform.fabric; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.geysermc.connector.GeyserLogger; public class GeyserFabricLogger implements GeyserLogger { + private final Logger logger = LogManager.getLogger("geyser-fabric"); + private boolean debug; public GeyserFabricLogger(boolean isDebug) { @@ -37,38 +41,38 @@ public class GeyserFabricLogger implements GeyserLogger { @Override public void severe(String message) { - System.out.println(message); + logger.fatal(message); } @Override public void severe(String message, Throwable error) { - System.out.println(message); + logger.fatal(message, error); } @Override public void error(String message) { - System.out.println(message); + logger.error(message); } @Override public void error(String message, Throwable error) { - System.out.println(message); + logger.error(message, error); } @Override public void warning(String message) { - System.out.println(message); + logger.warn(message); } @Override public void info(String message) { - System.out.println(message); + logger.info(message); } @Override public void debug(String message) { if (debug) { - info(message); + logger.info(message); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index fda3eb9ad..22d48013c 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -28,8 +28,9 @@ package org.geysermc.platform.fabric; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.server.dedicated.DedicatedServer; +import org.apache.logging.log4j.LogManager; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.bootstrap.GeyserBootstrap; @@ -76,7 +77,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); } catch (IOException ex) { - System.out.println(LanguageUtils.getLocaleStringLog("geyser.config.failed")); + LogManager.getLogger("geyser-fabric").error(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); } @@ -86,6 +87,14 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); + ServerLifecycleEvents.SERVER_STARTING.register((server) -> { + String ip = server.getServerIp(); + int port = server.getServerPort(); + if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { + this.geyserConfig.getRemote().setAddress(ip); + } + this.geyserConfig.getRemote().setPort(port); + }); } if (geyserConfig.getBedrock().isCloneRemotePort()) { @@ -94,6 +103,9 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo this.connector = GeyserConnector.start(PlatformType.ANDROID, this); + // Register onDisable so players are properly kicked + ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); this.geyserCommandManager = new GeyserFabricCommandManager(connector); From 6ccde86057c86cd2dd5d13da49d4fc8495ed4666 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 14:11:27 -0400 Subject: [PATCH 004/100] Getting server IP now works --- .../platform/fabric/GeyserFabricMod.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 22d48013c..d3aa79873 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -30,6 +30,8 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.block.Block; +import net.minecraft.util.registry.Registry; import org.apache.logging.log4j.LogManager; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserLogger; @@ -38,6 +40,7 @@ import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; @@ -85,30 +88,31 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - ServerLifecycleEvents.SERVER_STARTING.register((server) -> { + ServerLifecycleEvents.SERVER_STARTED.register((server) -> { + // Required to do this so we can get the proper IP and port if needed + if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { + this.geyserConfig.setAutoconfiguredRemote(true); String ip = server.getServerIp(); int port = server.getServerPort(); if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { this.geyserConfig.getRemote().setAddress(ip); } this.geyserConfig.getRemote().setPort(port); - }); - } + } - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); - } + if (geyserConfig.getBedrock().isCloneRemotePort()) { + geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + } - this.connector = GeyserConnector.start(PlatformType.ANDROID, this); + this.connector = GeyserConnector.start(PlatformType.ANDROID, this); + + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + + this.geyserCommandManager = new GeyserFabricCommandManager(connector); + }); // Register onDisable so players are properly kicked ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); - - this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); - - this.geyserCommandManager = new GeyserFabricCommandManager(connector); } @Override From 4b6f1a06b71f5b55cb970227c1c6c1c3eb568359 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 14:23:55 -0400 Subject: [PATCH 005/100] Remove unused imports --- .../java/org/geysermc/platform/fabric/GeyserFabricMod.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index d3aa79873..f008cb069 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -30,8 +30,6 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.block.Block; -import net.minecraft.util.registry.Registry; import org.apache.logging.log4j.LogManager; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserLogger; @@ -40,7 +38,6 @@ import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; From c34b63c8c67ac1837246776869181b561ec3cea0 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 18:43:02 -0400 Subject: [PATCH 006/100] Add proper commands support --- bootstrap/fabric/build.gradle | 3 + .../platform/fabric/GeyserFabricDumpInfo.java | 30 +++++++++ .../platform/fabric/GeyserFabricMod.java | 21 +++++- .../fabric/command/FabricCommandSender.java | 65 +++++++++++++++++++ .../command/GeyserFabricCommandExecutor.java | 54 +++++++++++++++ .../platform/fabric/command/ModInfo.java | 53 +++++++++++++++ 6 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 8377dab43..059b59d42 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -23,6 +23,9 @@ dependencies { // You may need to force-disable transitiveness on them. implementation 'org.geysermc:connector:1.1.0' + + compileOnly 'org.projectlombok:lombok:1.18.4' + annotationProcessor 'org.projectlombok:lombok:1.18.4' } repositories { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java index cd35e77f2..2c9917de9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -25,7 +25,37 @@ package org.geysermc.platform.fabric; +import lombok.Getter; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.server.MinecraftServer; +import org.geysermc.connector.common.serializer.AsteriskSerializer; import org.geysermc.connector.dump.BootstrapDumpInfo; +import org.geysermc.platform.fabric.command.ModInfo; +import java.util.ArrayList; +import java.util.List; + +@Getter public class GeyserFabricDumpInfo extends BootstrapDumpInfo { + + private String serverIP; + private int serverPort; + private List mods; + + public GeyserFabricDumpInfo(MinecraftServer server) { + super(); + if (AsteriskSerializer.showSensitive || (server.getServerIp() == null || server.getServerIp().equals("") || server.getServerIp().equals("0.0.0.0"))) { + this.serverIP = server.getServerIp(); + } else { + this.serverIP = "***"; + } + this.serverPort = server.getServerPort(); + this.mods = new ArrayList<>(); + + for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { + this.mods.add(new ModInfo(mod)); + } + } + } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index f008cb069..ea5210bbc 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -25,16 +25,20 @@ package org.geysermc.platform.fabric; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; import org.apache.logging.log4j.LogManager; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; @@ -42,11 +46,13 @@ import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.Map; import java.util.UUID; @Environment(EnvType.SERVER) @@ -54,6 +60,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo private GeyserConnector connector; private Path dataFolder; + private MinecraftServer server; private GeyserFabricCommandManager geyserCommandManager; private GeyserFabricConfiguration geyserConfig; @@ -87,6 +94,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo ServerLifecycleEvents.SERVER_STARTED.register((server) -> { // Required to do this so we can get the proper IP and port if needed + this.server = server; if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); String ip = server.getServerIp(); @@ -106,6 +114,17 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); this.geyserCommandManager = new GeyserFabricCommandManager(connector); + + // Start command building + // Set just "geyser" as the help command + LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") + .executes(new GeyserFabricCommandExecutor(connector, "help")); + for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { + // Register all subcommands as valid + builder.then(net.minecraft.server.command.CommandManager.literal( + command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey()))); + } + server.getCommandManager().getDispatcher().register(builder); }); // Register onDisable so players are properly kicked @@ -146,6 +165,6 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo @Override public BootstrapDumpInfo getDumpInfo() { - return new GeyserFabricDumpInfo(); + return new GeyserFabricDumpInfo(server); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java new file mode 100644 index 000000000..b73f85562 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.command; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.LiteralText; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandSender; + +public class FabricCommandSender implements CommandSender { + + private final ServerCommandSource source; + + public FabricCommandSender(ServerCommandSource source) { + this.source = source; + } + + @Override + public String getName() { + return source.getName(); + } + + @Override + public void sendMessage(String message) { + try { + source.getPlayer().sendMessage(new LiteralText(message), false); + } catch (CommandSyntaxException e) { // why + GeyserConnector.getInstance().getLogger().info(message); + } + } + + @Override + public boolean isConsole() { + try { + source.getPlayer(); + return false; + } catch (CommandSyntaxException e) { + return true; + } + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java new file mode 100644 index 000000000..290e452c6 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.server.command.ServerCommandSource; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.GeyserCommand; + +public class GeyserFabricCommandExecutor implements Command { + + private final String commandName; + private final GeyserConnector connector; + + public GeyserFabricCommandExecutor(GeyserConnector connector, String commandName) { + this.commandName = commandName; + this.connector = connector; + } + + @Override + public int run(CommandContext context) { + ServerCommandSource source = (ServerCommandSource) context.getSource(); + getCommand(commandName).execute(new FabricCommandSender(source), new String[0]); + return 0; + } + + private GeyserCommand getCommand(String label) { + return connector.getCommandManager().getCommands().get(label); + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java new file mode 100644 index 000000000..722fd2ded --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.command; + +import lombok.Getter; +import net.fabricmc.loader.api.ModContainer; + +import java.util.ArrayList; +import java.util.List; + +/** + * A wrapper for Fabric mod information to be presented in a Geyser dump + */ +@Getter +public class ModInfo { + + private String name; + private String id; + private String version; + private List authors; + + public ModInfo(ModContainer mod) { + this.name = mod.getMetadata().getName(); + this.id = mod.getMetadata().getId(); + this.authors = new ArrayList<>(); + mod.getMetadata().getAuthors().forEach((person) -> this.authors.add(person.getName())); + this.version = mod.getMetadata().getVersion().getFriendlyString(); + } + +} From 64d5cf51d13bf1f0ed9203ed4e290638c051183b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Tue, 6 Oct 2020 18:53:11 -0400 Subject: [PATCH 007/100] Create README.md --- bootstrap/fabric/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 bootstrap/fabric/README.md diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md new file mode 100644 index 000000000..6c9e6b304 --- /dev/null +++ b/bootstrap/fabric/README.md @@ -0,0 +1,8 @@ +# Geyser-Fabric + +[![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) + +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) + +Geyser-Fabric is Geyser specifically built for the Fabric modding platform. From 7a91e0a80d14a43119b04f3a71dc87ffee8a3c05 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 22:45:15 -0400 Subject: [PATCH 008/100] Start on compiling --- bootstrap/fabric/build.gradle | 30 ++++++++++++++++++++++++++++++ bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 059b59d42..6ea04cb5d 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -1,6 +1,7 @@ plugins { id 'fabric-loom' version '0.5-SNAPSHOT' id 'maven-publish' + id 'com.github.johnrengelman.shadow' version '6.0.0' } sourceCompatibility = JavaVersion.VERSION_1_8 @@ -23,6 +24,11 @@ dependencies { // You may need to force-disable transitiveness on them. implementation 'org.geysermc:connector:1.1.0' + shadow('org.geysermc:connector:1.1.0') { +// exclude group: 'org.w3c' +// exclude group: 'org.xml' +// exclude group: 'javax.xml' + } compileOnly 'org.projectlombok:lombok:1.18.4' annotationProcessor 'org.projectlombok:lombok:1.18.4' @@ -74,10 +80,34 @@ task sourcesJar(type: Jar, dependsOn: classes) { from sourceSets.main.allSource } +shadowJar { + configurations = [project.configurations.shadow] + //relocate 'org.apache', 'geyser.org.apache' + relocate 'org.reflections', 'geyser.org.reflections' + relocate 'org.dom4j', 'geyser.org.dom4j' + relocate 'javax.xml', 'geyser.javaxxml' + relocate 'org.xml', 'geyser.xml' + //relocate 'org.w3c', 'geyser.w3c' +} + jar { from "LICENSE" } +remapJar { + dependsOn(shadowJar) + input.set shadowJar.archiveFile.get() +} +// +//import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation +// +//task relocateShadowJar(type: ConfigureShadowRelocation) { +// target = tasks.shadowJar +// prefix = "org.geyser.platform.fabric.relocate" +//} +// +//tasks.shadowJar.dependsOn tasks.relocateShadowJar + // configure the maven publication publishing { publications { diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index fbcb2816c..7fe0d5d14 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -8,7 +8,7 @@ loader_version=0.10.1+build.209 # Mod Properties mod_version=1.0-SNAPSHOT maven_group=org.geysermc.platform -archives_base_name=fabric +archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html fabric_version=0.23.0+build.410-1.16 From b293c3478a1c323ea6443fc66cfd850ed5a96f60 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 18:35:35 -0400 Subject: [PATCH 009/100] It compiles! :D --- bootstrap/fabric/build.gradle | 25 ++++++------------- .../platform/fabric/GeyserFabricMod.java | 2 +- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 6ea04cb5d..728c14641 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -1,9 +1,13 @@ plugins { id 'fabric-loom' version '0.5-SNAPSHOT' id 'maven-publish' - id 'com.github.johnrengelman.shadow' version '6.0.0' + id 'com.github.johnrengelman.shadow' version '6.1.0' + id 'java' } +apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: 'java' + sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -24,17 +28,15 @@ dependencies { // You may need to force-disable transitiveness on them. implementation 'org.geysermc:connector:1.1.0' - shadow('org.geysermc:connector:1.1.0') { -// exclude group: 'org.w3c' -// exclude group: 'org.xml' -// exclude group: 'javax.xml' - } + shadow 'org.geysermc:connector:1.1.0' compileOnly 'org.projectlombok:lombok:1.18.4' annotationProcessor 'org.projectlombok:lombok:1.18.4' } repositories { + mavenLocal() + maven { url = uri('https://repo.nukkitx.com/maven-releases/') } @@ -82,12 +84,10 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] - //relocate 'org.apache', 'geyser.org.apache' relocate 'org.reflections', 'geyser.org.reflections' relocate 'org.dom4j', 'geyser.org.dom4j' relocate 'javax.xml', 'geyser.javaxxml' relocate 'org.xml', 'geyser.xml' - //relocate 'org.w3c', 'geyser.w3c' } jar { @@ -98,15 +98,6 @@ remapJar { dependsOn(shadowJar) input.set shadowJar.archiveFile.get() } -// -//import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation -// -//task relocateShadowJar(type: ConfigureShadowRelocation) { -// target = tasks.shadowJar -// prefix = "org.geyser.platform.fabric.relocate" -//} -// -//tasks.shadowJar.dependsOn tasks.relocateShadowJar // configure the maven publication publishing { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index ea5210bbc..c5058a130 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -109,7 +109,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); } - this.connector = GeyserConnector.start(PlatformType.ANDROID, this); + this.connector = GeyserConnector.start(PlatformType.FABRIC, this); this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); From 977ce4bbece4de4693c9377e6de48f39d26072fd Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 19:02:41 -0400 Subject: [PATCH 010/100] Guess we don't need any relocations --- bootstrap/fabric/build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 728c14641..542fb58c6 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -84,10 +84,6 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] - relocate 'org.reflections', 'geyser.org.reflections' - relocate 'org.dom4j', 'geyser.org.dom4j' - relocate 'javax.xml', 'geyser.javaxxml' - relocate 'org.xml', 'geyser.xml' } jar { From 105f4f0a32eddadc9f078874270537d989ec3619 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 19:44:13 -0400 Subject: [PATCH 011/100] Fix console chat output --- .../geysermc/platform/fabric/command/FabricCommandSender.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index b73f85562..3ec548143 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -30,6 +30,7 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; +import org.geysermc.connector.common.ChatColor; public class FabricCommandSender implements CommandSender { @@ -49,7 +50,7 @@ public class FabricCommandSender implements CommandSender { try { source.getPlayer().sendMessage(new LiteralText(message), false); } catch (CommandSyntaxException e) { // why - GeyserConnector.getInstance().getLogger().info(message); + GeyserConnector.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); } } From 9e62c6369ce2aca0fbf690ab7c83aa1d3de86075 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:01:01 -0400 Subject: [PATCH 012/100] Jenkinsfile attempt --- bootstrap/fabric/Jenkinsfile | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 bootstrap/fabric/Jenkinsfile diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile new file mode 100644 index 000000000..3e8155cd9 --- /dev/null +++ b/bootstrap/fabric/Jenkinsfile @@ -0,0 +1,62 @@ +pipeline { + agent any + tools { + jdk 'Java 8' + } + options { + buildDiscarder(logRotator(artifactNumToKeepStr: '20')) + } + stages { + stage ('Build') { + steps { + sh './gradlew clean build' + } + post { + success { + archiveArtifacts artifacts: 'bootstrap/**/target/*.jar', excludes: 'bootstrap/**/target/original-*.jar', fingerprint: true + archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/*-dev.jar' 'build/libs/*-sources*jar' 'build/libs/*-all.jar', fingerprint: true + } + } + } + } + + post { + always { + script { + def changeLogSets = currentBuild.changeSets + def message = "**Changes:**" + + if (changeLogSets.size() == 0) { + message += "\n*No changes.*" + } else { + def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "") + def count = 0; + def extra = 0; + for (int i = 0; i < changeLogSets.size(); i++) { + def entries = changeLogSets[i].items + for (int j = 0; j < entries.length; j++) { + if (count <= 10) { + def entry = entries[j] + def commitId = entry.commitId.substring(0, 6) + message += "\n - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}" + count++ + } else { + extra++; + } + } + } + + if (extra != 0) { + message += "\n - ${extra} more commits" + } + } + + env.changes = message + } + deleteDir() + withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { + discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'Cloudburst Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK + } + } + } +} From ad42c800cd0180ef50909dc2f550723b9897fb9c Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:04:08 -0400 Subject: [PATCH 013/100] Remove erroneous line --- bootstrap/fabric/Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 3e8155cd9..42f09947e 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -13,7 +13,6 @@ pipeline { } post { success { - archiveArtifacts artifacts: 'bootstrap/**/target/*.jar', excludes: 'bootstrap/**/target/original-*.jar', fingerprint: true archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/*-dev.jar' 'build/libs/*-sources*jar' 'build/libs/*-all.jar', fingerprint: true } } From f99cbfa231129353409643f8b777a9405477f3c2 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:21:46 -0400 Subject: [PATCH 014/100] Maybe this works? --- bootstrap/fabric/Jenkinsfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 42f09947e..937a9c3d4 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -13,7 +13,11 @@ pipeline { } post { success { - archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/*-dev.jar' 'build/libs/*-sources*jar' 'build/libs/*-all.jar', fingerprint: true + archiveArtifacts artifacts: 'build/libs/*.jar', excludes: { + 'build/libs/*-dev.jar' + 'build/libs/*-sources*jar' + 'build/libs/*-all.jar' + }, fingerprint: true } } } From 293f691d39dd8343f3dbd562d02b1d0b9a2489b3 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:28:43 -0400 Subject: [PATCH 015/100] Manually define Gradle --- bootstrap/fabric/Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 937a9c3d4..abd106ec1 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -1,6 +1,7 @@ pipeline { agent any tools { + gradle 'Gradle 6' jdk 'Java 8' } options { @@ -9,7 +10,7 @@ pipeline { stages { stage ('Build') { steps { - sh './gradlew clean build' + sh 'gradle clean build' } post { success { From 7b0c1e9a05bdeebaa24ce654e147057a53657488 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:29:39 -0400 Subject: [PATCH 016/100] Generify Gradle --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index abd106ec1..f5251f92e 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -1,7 +1,7 @@ pipeline { agent any tools { - gradle 'Gradle 6' + gradle 'Gradle' jdk 'Java 8' } options { From 0e77f20f86e19e682d21521bc8aff46aa434c990 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:37:23 -0400 Subject: [PATCH 017/100] Specify Fabric repository --- bootstrap/fabric/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 542fb58c6..3f38fc840 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -37,6 +37,10 @@ dependencies { repositories { mavenLocal() + maven { + url = uri('https://maven.fabricmc.net/') + } + maven { url = uri('https://repo.nukkitx.com/maven-releases/') } From ca65f9f45a10e4fe7db8a7db9afffab363597fb7 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 20:59:09 -0400 Subject: [PATCH 018/100] Fix ./gradlew usage --- bootstrap/fabric/Jenkinsfile | 3 +-- bootstrap/fabric/build.gradle | 4 ---- .../fabric/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes 3 files changed, 1 insertion(+), 6 deletions(-) create mode 100644 bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index f5251f92e..937a9c3d4 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -1,7 +1,6 @@ pipeline { agent any tools { - gradle 'Gradle' jdk 'Java 8' } options { @@ -10,7 +9,7 @@ pipeline { stages { stage ('Build') { steps { - sh 'gradle clean build' + sh './gradlew clean build' } post { success { diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 3f38fc840..542fb58c6 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -37,10 +37,6 @@ dependencies { repositories { mavenLocal() - maven { - url = uri('https://maven.fabricmc.net/') - } - maven { url = uri('https://repo.nukkitx.com/maven-releases/') } diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 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 literal 0 HcmV?d00001 From 56b70927f2c087495904a258e81758b53b65a604 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 21:05:42 -0400 Subject: [PATCH 019/100] Fix archiving --- bootstrap/fabric/Jenkinsfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 937a9c3d4..58bfc96ad 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -13,11 +13,7 @@ pipeline { } post { success { - archiveArtifacts artifacts: 'build/libs/*.jar', excludes: { - 'build/libs/*-dev.jar' - 'build/libs/*-sources*jar' - 'build/libs/*-all.jar' - }, fingerprint: true + archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/Geyser-Fabric-*-.jar', fingerprint: true } } } From ae3896d1d00c731417d9a4a08a158abea8a6978b Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 7 Oct 2020 22:42:17 -0400 Subject: [PATCH 020/100] Add command permissions system --- .../platform/fabric/GeyserFabricDumpInfo.java | 1 - .../platform/fabric/GeyserFabricMod.java | 38 +++++++++++++++-- .../fabric/GeyserFabricPermissions.java | 42 +++++++++++++++++++ .../fabric/{command => }/ModInfo.java | 2 +- .../command/GeyserFabricCommandExecutor.java | 15 ++++++- .../src/main/resources/fabric.mixins.json | 13 ------ .../fabric/src/main/resources/fabric.mod.json | 3 -- .../fabric/src/main/resources/permissions.yml | 10 +++++ 8 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java rename bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/{command => }/ModInfo.java (97%) delete mode 100644 bootstrap/fabric/src/main/resources/fabric.mixins.json create mode 100644 bootstrap/fabric/src/main/resources/permissions.yml diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java index 2c9917de9..1b9d68a9c 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -31,7 +31,6 @@ import net.fabricmc.loader.api.ModContainer; import net.minecraft.server.MinecraftServer; import org.geysermc.connector.common.serializer.AsteriskSerializer; import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.geysermc.platform.fabric.command.ModInfo; import java.util.ArrayList; import java.util.List; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index c5058a130..0e395dcee 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -50,16 +50,19 @@ import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.function.Function; @Environment(EnvType.SERVER) public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBootstrap { private GeyserConnector connector; private Path dataFolder; + private List playerCommands; private MinecraftServer server; private GeyserFabricCommandManager geyserCommandManager; @@ -83,6 +86,8 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); + File permissionsFile = fileOrCopiedFromResource(dataFolder.resolve("permissions.yml").toFile(), "permissions.yml"); + this.playerCommands = Arrays.asList(FileUtils.loadConfig(permissionsFile, GeyserFabricPermissions.class).getCommands()); } catch (IOException ex) { LogManager.getLogger("geyser-fabric").error(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); @@ -118,11 +123,12 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo // Start command building // Set just "geyser" as the help command LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") - .executes(new GeyserFabricCommandExecutor(connector, "help")); + .executes(new GeyserFabricCommandExecutor(connector, "help", !playerCommands.contains("help"))); for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { // Register all subcommands as valid builder.then(net.minecraft.server.command.CommandManager.literal( - command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey()))); + command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey(), + !playerCommands.contains(command.getKey())))); } server.getCommandManager().getDispatcher().register(builder); }); @@ -167,4 +173,28 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo public BootstrapDumpInfo getDumpInfo() { return new GeyserFabricDumpInfo(server); } + + private File fileOrCopiedFromResource(File file, String name) throws IOException { + if (!file.exists()) { + //noinspection ResultOfMethodCallIgnored + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + InputStream input = GeyserFabricMod.class.getResourceAsStream("/" + name); // resources need leading "/" prefix + + byte[] bytes = new byte[input.available()]; + + //noinspection ResultOfMethodCallIgnored + input.read(bytes); + + for(char c : new String(bytes).toCharArray()) { + fos.write(c); + } + + fos.flush(); + input.close(); + fos.close(); + } + + return file; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java new file mode 100644 index 000000000..51a7cb2e4 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; + +/** + * A class outline of the permissions.yml file + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class GeyserFabricPermissions { + + @Getter + @JsonProperty("commands") + private String[] commands; + +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java similarity index 97% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java rename to bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java index 722fd2ded..159678766 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/ModInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.command; +package org.geysermc.platform.fabric; import lombok.Getter; import net.fabricmc.loader.api.ModContainer; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index 290e452c6..1064af3a9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -30,21 +30,32 @@ import com.mojang.brigadier.context.CommandContext; import net.minecraft.server.command.ServerCommandSource; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.GeyserCommand; +import org.geysermc.connector.utils.LanguageUtils; public class GeyserFabricCommandExecutor implements Command { private final String commandName; private final GeyserConnector connector; + /** + * Whether the command requires an OP permission level of 2 or greater + */ + private final boolean requiresPermission; - public GeyserFabricCommandExecutor(GeyserConnector connector, String commandName) { + public GeyserFabricCommandExecutor(GeyserConnector connector, String commandName, boolean requiresPermission) { this.commandName = commandName; this.connector = connector; + this.requiresPermission = requiresPermission; } @Override public int run(CommandContext context) { ServerCommandSource source = (ServerCommandSource) context.getSource(); - getCommand(commandName).execute(new FabricCommandSender(source), new String[0]); + FabricCommandSender sender = new FabricCommandSender(source); + if (requiresPermission && !source.hasPermissionLevel(2)) { + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); + return 0; + } + getCommand(commandName).execute(sender, new String[0]); return 0; } diff --git a/bootstrap/fabric/src/main/resources/fabric.mixins.json b/bootstrap/fabric/src/main/resources/fabric.mixins.json deleted file mode 100644 index a1f71d182..000000000 --- a/bootstrap/fabric/src/main/resources/fabric.mixins.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "org.geysermc.platform.fabric.mixin", - "compatibilityLevel": "JAVA_8", - "mixins": [ - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 10defc82d..1655cc212 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -19,9 +19,6 @@ "org.geysermc.platform.fabric.GeyserFabricMod" ] }, - "mixins": [ - "fabric.mixins.json" - ], "depends": { "fabricloader": ">=0.10.1+build.209", "fabric": "*", diff --git a/bootstrap/fabric/src/main/resources/permissions.yml b/bootstrap/fabric/src/main/resources/permissions.yml new file mode 100644 index 000000000..a51d3169a --- /dev/null +++ b/bootstrap/fabric/src/main/resources/permissions.yml @@ -0,0 +1,10 @@ +# Uncomment any commands that you wish to be run by clients +# Commented commands require an OP permission of 2 or greater +commands: +# - dump + - help + - offhand +# - list +# - reload +# - shutdown +# - version From f82329b34f64c98e62578880ebf4abcb036a925e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 7 Oct 2020 23:05:23 -0400 Subject: [PATCH 021/100] Add Jenkins builds to the README --- bootstrap/fabric/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index 6c9e6b304..aca64c623 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -3,6 +3,7 @@ [![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) Geyser-Fabric is Geyser specifically built for the Fabric modding platform. From 4d925da68a3b2dd3276eeca8d740265bc9129494 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 7 Oct 2020 23:05:52 -0400 Subject: [PATCH 022/100] Add specific Jenkins link --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index aca64c623..b964cd98f 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -3,7 +3,7 @@ [![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/) +[![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) Geyser-Fabric is Geyser specifically built for the Fabric modding platform. From 856ce6b588d7eaf49f20739f1a168a047bfd0c62 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Thu, 8 Oct 2020 12:54:53 -0400 Subject: [PATCH 023/100] Exclude all irrelevant builds --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 58bfc96ad..c830b4e53 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -13,7 +13,7 @@ pipeline { } post { success { - archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/Geyser-Fabric-*-.jar', fingerprint: true + archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/Geyser-Fabric-*-sources*.jar,build/libs/Geyser-Fabric-*-all*.jar', fingerprint: true } } } From c426c335d7b55918443817912c6361b02b720113 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sun, 11 Oct 2020 23:15:22 -0400 Subject: [PATCH 024/100] Fix reloading Geyser --- bootstrap/fabric/Jenkinsfile | 2 +- .../platform/fabric/GeyserFabricMod.java | 79 +++++++++++-------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index c830b4e53..9a3118e15 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -9,7 +9,7 @@ pipeline { stages { stage ('Build') { steps { - sh './gradlew clean build' + sh './gradlew clean build --refresh-dependencies' } post { success { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 0e395dcee..b716e1a8b 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -97,50 +97,65 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - ServerLifecycleEvents.SERVER_STARTED.register((server) -> { - // Required to do this so we can get the proper IP and port if needed - this.server = server; - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - String ip = server.getServerIp(); - int port = server.getServerPort(); - if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { - this.geyserConfig.getRemote().setAddress(ip); - } - this.geyserConfig.getRemote().setPort(port); + if (server == null) { + // Server has yet to start + // Set as an event so we can get the proper IP and port if needed + ServerLifecycleEvents.SERVER_STARTED.register((server) -> { + this.server = server; + startGeyser(); + }); + + // Register onDisable so players are properly kicked + ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); + } else { + // Server has started and this is a reload + startGeyser(); + } + } + + /** + * Initialize core Geyser. + * A function, as it needs to be called in different places depending on if Geyser is being reloaded or not. + */ + public void startGeyser() { + if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { + this.geyserConfig.setAutoconfiguredRemote(true); + String ip = server.getServerIp(); + int port = server.getServerPort(); + if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { + this.geyserConfig.getRemote().setAddress(ip); } + this.geyserConfig.getRemote().setPort(port); + } - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); - } + if (geyserConfig.getBedrock().isCloneRemotePort()) { + geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + } - this.connector = GeyserConnector.start(PlatformType.FABRIC, this); + this.connector = GeyserConnector.start(PlatformType.FABRIC, this); - this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); - this.geyserCommandManager = new GeyserFabricCommandManager(connector); + this.geyserCommandManager = new GeyserFabricCommandManager(connector); - // Start command building - // Set just "geyser" as the help command - LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") - .executes(new GeyserFabricCommandExecutor(connector, "help", !playerCommands.contains("help"))); - for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { - // Register all subcommands as valid - builder.then(net.minecraft.server.command.CommandManager.literal( - command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey(), - !playerCommands.contains(command.getKey())))); - } - server.getCommandManager().getDispatcher().register(builder); - }); - - // Register onDisable so players are properly kicked - ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); + // Start command building + // Set just "geyser" as the help command + LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") + .executes(new GeyserFabricCommandExecutor(connector, "help", !playerCommands.contains("help"))); + for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { + // Register all subcommands as valid + builder.then(net.minecraft.server.command.CommandManager.literal( + command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey(), + !playerCommands.contains(command.getKey())))); + } + server.getCommandManager().getDispatcher().register(builder); } @Override public void onDisable() { if (connector != null) { connector.shutdown(); + connector = null; } } From a9b414c675083b0124e60b1413689836570920ad Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Sun, 25 Oct 2020 17:29:19 +0100 Subject: [PATCH 025/100] Add LAN games support. --- .../platform/fabric/GeyserFabricMod.java | 36 +++++++---- .../fabric/GeyserServerPortGetter.java | 48 +++++++++++++++ .../mixin/client/IntegratedServerMixin.java | 59 +++++++++++++++++++ .../server/MinecraftDedicatedServerMixin.java | 58 ++++++++++++++++++ .../fabric/src/main/resources/fabric.mod.json | 7 ++- .../main/resources/geyser-fabric.mixins.json | 14 +++++ 6 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java create mode 100644 bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index b716e1a8b..dd5154267 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -28,7 +28,7 @@ package org.geysermc.platform.fabric; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; +import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; @@ -57,8 +57,9 @@ import java.nio.file.Path; import java.util.*; import java.util.function.Function; -@Environment(EnvType.SERVER) -public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBootstrap { +public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { + + private static GeyserFabricMod instance; private GeyserConnector connector; private Path dataFolder; @@ -71,8 +72,14 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo private IGeyserPingPassthrough geyserPingPassthrough; @Override - public void onInitializeServer() { + public void onInitialize() { + instance = this; + this.onEnable(); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { + // Set as an event so we can get the proper IP and port if needed + ServerLifecycleEvents.SERVER_STARTED.register(this::startGeyser); + } } @Override @@ -99,29 +106,27 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo if (server == null) { // Server has yet to start - // Set as an event so we can get the proper IP and port if needed - ServerLifecycleEvents.SERVER_STARTED.register((server) -> { - this.server = server; - startGeyser(); - }); - // Register onDisable so players are properly kicked ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); } else { // Server has started and this is a reload - startGeyser(); + startGeyser(this.server); } } /** * Initialize core Geyser. * A function, as it needs to be called in different places depending on if Geyser is being reloaded or not. + * + * @param server The minecraft server. */ - public void startGeyser() { + public void startGeyser(MinecraftServer server) { + this.server = server; + if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); String ip = server.getServerIp(); - int port = server.getServerPort(); + int port = ((GeyserServerPortGetter) server).geyser$getServerPort(); if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { this.geyserConfig.getRemote().setAddress(ip); } @@ -157,6 +162,7 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo connector.shutdown(); connector = null; } + this.server = null; } @Override @@ -212,4 +218,8 @@ public class GeyserFabricMod implements DedicatedServerModInitializer, GeyserBoo return file; } + + public static GeyserFabricMod getInstance() { + return instance; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java new file mode 100644 index 000000000..5af7775a8 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric; + +import net.minecraft.server.MinecraftServer; + +/** + * Represents a getter to the server port in the dedicated server and in the integrated server. + */ +public interface GeyserServerPortGetter { + /** + * Returns the server port. + * + *
    + *
  • If it's a dedicated server, it will return the server port specified in the {@code server.properties} file.
  • + *
  • If it's an integrated server, it will return the LAN port if opened, else -1.
  • + *
+ * + * The reason is that {@link MinecraftServer#getServerPort()} doesn't return the LAN port if it's the integrated server, + * and changing the behavior of this method via a mixin should be avoided as it could have unexpected consequences. + * + * @return The server port. + */ + int geyser$getServerPort(); +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java new file mode 100644 index 000000000..a84f71110 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.mixin.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.world.GameMode; +import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Environment(EnvType.CLIENT) +@Mixin(IntegratedServer.class) +public class IntegratedServerMixin implements GeyserServerPortGetter { + @Shadow + private int lanPort; + + @Inject(method = "openToLan", at = @At("RETURN")) + private void onOpenToLan(GameMode gameMode, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) { + if (cir.getReturnValueZ()) { + // If the LAN is opened, starts Geyser. + GeyserFabricMod.getInstance().startGeyser((MinecraftServer) (Object) this); + } + } + + @Override + public int geyser$getServerPort() { + return this.lanPort; + } +} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java new file mode 100644 index 000000000..eec6af74f --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.platform.fabric.mixin.server; + +import com.mojang.authlib.GameProfileRepository; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.datafixers.DataFixer; +import net.minecraft.resource.ResourcePackManager; +import net.minecraft.resource.ServerResourceManager; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.WorldGenerationProgressListenerFactory; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; +import net.minecraft.util.UserCache; +import net.minecraft.util.registry.DynamicRegistryManager; +import net.minecraft.world.SaveProperties; +import net.minecraft.world.level.storage.LevelStorage; +import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.spongepowered.asm.mixin.Mixin; + +import java.net.Proxy; + +@Mixin(MinecraftDedicatedServer.class) +public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter +{ + // Constructor to compile + public MinecraftDedicatedServerMixin(Thread thread, DynamicRegistryManager.Impl impl, LevelStorage.Session session, SaveProperties saveProperties, ResourcePackManager resourcePackManager, Proxy proxy, DataFixer dataFixer, ServerResourceManager serverResourceManager, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { + super(thread, impl, session, saveProperties, resourcePackManager, proxy, dataFixer, serverResourceManager, minecraftSessionService, gameProfileRepository, userCache, worldGenerationProgressListenerFactory); + } + + @Override + public int geyser$getServerPort() { + return this.getServerPort(); + } +} diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 1655cc212..55f5ceb70 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -13,12 +13,15 @@ }, "license": "MIT", "icon": "assets/fabric/icon.png", - "environment": "server", + "environment": "*", "entrypoints": { - "server": [ + "main": [ "org.geysermc.platform.fabric.GeyserFabricMod" ] }, + "mixins": [ + "geyser-fabric.mixins.json" + ], "depends": { "fabricloader": ">=0.10.1+build.209", "fabric": "*", diff --git a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json new file mode 100644 index 000000000..3965f9781 --- /dev/null +++ b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "org.geysermc.platform.fabric.mixin", + "compatibilityLevel": "JAVA_8", + "client": [ + "client.IntegratedServerMixin" + ], + "server": [ + "server.MinecraftDedicatedServerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From 4883a207972fde0a31e0e0506f5aee1be89eab2b Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sun, 25 Oct 2020 16:22:50 -0400 Subject: [PATCH 026/100] Add load complete message and don't null the server if reloading --- .../geysermc/platform/fabric/GeyserFabricMod.java | 11 ++++++++--- .../fabric/command/GeyserFabricCommandExecutor.java | 4 ++++ .../fabric/mixin/client/IntegratedServerMixin.java | 12 ++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index dd5154267..8767df018 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -26,7 +26,7 @@ package org.geysermc.platform.fabric; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import net.fabricmc.api.DedicatedServerModInitializer; +import lombok.Setter; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -55,12 +55,14 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.util.*; -import java.util.function.Function; public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private static GeyserFabricMod instance; + @Setter + private boolean reloading; + private GeyserConnector connector; private Path dataFolder; private List playerCommands; @@ -111,6 +113,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { } else { // Server has started and this is a reload startGeyser(this.server); + reloading = false; } } @@ -162,7 +165,9 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { connector.shutdown(); connector = null; } - this.server = null; + if (!reloading) { + this.server = null; + } } @Override diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index 1064af3a9..706ef9502 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -31,6 +31,7 @@ import net.minecraft.server.command.ServerCommandSource; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.platform.fabric.GeyserFabricMod; public class GeyserFabricCommandExecutor implements Command { @@ -55,6 +56,9 @@ public class GeyserFabricCommandExecutor implements Command sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } + if (this.commandName.equals("reload")) { + GeyserFabricMod.getInstance().setReloading(true); + } getCommand(commandName).execute(sender, new String[0]); return 0; } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java index a84f71110..5415a9d3a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -27,11 +27,16 @@ package org.geysermc.platform.fabric.mixin.client; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.text.LiteralText; import net.minecraft.world.GameMode; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -44,11 +49,18 @@ public class IntegratedServerMixin implements GeyserServerPortGetter { @Shadow private int lanPort; + @Shadow @Final private MinecraftClient client; + @Inject(method = "openToLan", at = @At("RETURN")) private void onOpenToLan(GameMode gameMode, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) { if (cir.getReturnValueZ()) { // If the LAN is opened, starts Geyser. GeyserFabricMod.getInstance().startGeyser((MinecraftServer) (Object) this); + // Ensure player locale has been loaded, in case it's different from Java system language + LanguageUtils.loadGeyserLocale(this.client.options.language); + // Give indication that Geyser is loaded + this.client.player.sendMessage(new LiteralText(LanguageUtils.getPlayerLocaleString("geyser.core.start", + this.client.options.language, "localhost", String.valueOf(this.lanPort))), false); } } From 7455b78cbf99b3597d8bf157829848379ed0007f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sun, 25 Oct 2020 23:19:56 -0400 Subject: [PATCH 027/100] Make downloading more clear --- bootstrap/fabric/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index b964cd98f..438431331 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -2,8 +2,9 @@ [![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) +Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) + [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) Geyser-Fabric is Geyser specifically built for the Fabric modding platform. From 6f698993ab9742efacfc092816f761a151385f5f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sun, 25 Oct 2020 23:31:52 -0400 Subject: [PATCH 028/100] Add reference to the Geyser wiki --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index 438431331..d50255b1f 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -7,4 +7,4 @@ Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) -Geyser-Fabric is Geyser specifically built for the Fabric modding platform. +Geyser-Fabric is Geyser specifically built for the Fabric modding platform. For more details, see [here](https://github.com/GeyserMC/Geyser/wiki/Geyser-Fabric). From 3d994db0f2389a60780eeb06532ee0802f96ca27 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 27 Oct 2020 13:51:54 -0400 Subject: [PATCH 029/100] Move to OpenCollab domain --- bootstrap/fabric/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 542fb58c6..6a4b81cf0 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -38,11 +38,11 @@ repositories { mavenLocal() maven { - url = uri('https://repo.nukkitx.com/maven-releases/') + url = uri('https://repo.opencollab.dev/maven-releases/') } maven { - url = uri('https://repo.nukkitx.com/maven-snapshots/') + url = uri('https://repo.opencollab.dev/maven-snapshots/') } maven { From b11d2bcd3f286c5a4058a7b5e4f2504d980ea068 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sat, 7 Nov 2020 23:23:23 -0500 Subject: [PATCH 030/100] Support Minecraft 1.16.3 and 1.16.4 --- bootstrap/fabric/src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 55f5ceb70..89cbd12b5 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.10.1+build.209", "fabric": "*", - "minecraft": "1.16.3" + "minecraft": ">=1.16.3" } } From 566113fa1ea09e03e6fbffa6608cf4e113449f99 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 11 Nov 2020 23:35:44 -0500 Subject: [PATCH 031/100] Fix LAN support compiled? --- bootstrap/fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 6a4b81cf0..de324a10b 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -84,6 +84,7 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] + relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") } jar { From a3de72fed3da3a0471ab399fcc10fc7bd6474e97 Mon Sep 17 00:00:00 2001 From: Redned Date: Sat, 14 Nov 2020 17:53:59 -0600 Subject: [PATCH 032/100] Use PlatformType in common module --- .../main/java/org/geysermc/platform/fabric/GeyserFabricMod.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 8767df018..4f1eed1c9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -34,12 +34,12 @@ import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import org.apache.logging.log4j.LogManager; +import org.geysermc.common.PlatformType; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; From b4d3fd088aa7c2c3f4c4a70ae51485c075b772ce Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 17 Nov 2020 13:32:13 -0500 Subject: [PATCH 033/100] Update to 1.16.100 --- bootstrap/fabric/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index de324a10b..0f8f35cbc 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.1.0' - shadow 'org.geysermc:connector:1.1.0' + implementation 'org.geysermc:connector:1.2.0-SNAPSHOT' + shadow 'org.geysermc:connector:1.2.0-SNAPSHOT' compileOnly 'org.projectlombok:lombok:1.18.4' annotationProcessor 'org.projectlombok:lombok:1.18.4' From be8329722e5ac68851880060fd47fc337fbff826 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 7 Jan 2021 09:56:06 +0000 Subject: [PATCH 034/100] Fix builds for new CI --- bootstrap/fabric/Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 9a3118e15..0efa73dfb 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -1,6 +1,7 @@ pipeline { agent any tools { + gradle 'Gradle 6' jdk 'Java 8' } options { @@ -9,7 +10,7 @@ pipeline { stages { stage ('Build') { steps { - sh './gradlew clean build --refresh-dependencies' + sh 'gradle clean build --refresh-dependencies' } post { success { From b51173ea97ab63a383ff6a9377da46ccdb72f74d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:13:13 -0500 Subject: [PATCH 035/100] Attempt to use Artifactory --- bootstrap/fabric/Jenkinsfile | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 0efa73dfb..4b6b1d315 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -18,6 +18,41 @@ pipeline { } } } + + stage ('Deploy') { + when { + branch "master" + } + + steps { + sh 'mvn javadoc:jar source:jar deploy -DskipTests' + rtGradleDeployer( + id: "GRADLE_DEPLOYER", + serverId: "opencollab-artifactory", + releaseRepo: "maven-releases", + snapshotRepo: "maven-snapshots" + ) + rtGradleResolver( + id: "GRADLE_RESOLVER", + serverId: "opencollab-artifactory", + releaseRepo: "release", + snapshotRepo: "snapshot" + ) + rtGradleRun ( + usesPlugin: true, + tool: GRADLE_TOOL, + rootDir: "/", + buildFile: 'build.gradle', + tasks: 'clean artifactoryPublish', + deployerId: "GRADLE_DEPLOYER", + resolverId: "GRADLE_RESOLVER" + ) + rtPublishBuildInfo( + serverId: "opencollab-artifactory" + ) + } + } + } } post { From 4255240b6e17682b860bd52318dd0d0661e60c4e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:14:41 -0500 Subject: [PATCH 036/100] Attempt 2 --- bootstrap/fabric/Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 4b6b1d315..1087ca373 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -52,7 +52,6 @@ pipeline { ) } } - } } post { From 029522c2fc9d9d530e3788ac04be6443880753e9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:18:41 -0500 Subject: [PATCH 037/100] Attempt 3 and then I start actually looking at docs --- bootstrap/fabric/Jenkinsfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 1087ca373..ca2d4596b 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -25,7 +25,6 @@ pipeline { } steps { - sh 'mvn javadoc:jar source:jar deploy -DskipTests' rtGradleDeployer( id: "GRADLE_DEPLOYER", serverId: "opencollab-artifactory", @@ -35,8 +34,6 @@ pipeline { rtGradleResolver( id: "GRADLE_RESOLVER", serverId: "opencollab-artifactory", - releaseRepo: "release", - snapshotRepo: "snapshot" ) rtGradleRun ( usesPlugin: true, From cd9dde9796491b0479ccff596f0c291e3e15f3bd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:32:10 -0500 Subject: [PATCH 038/100] Attempt 4 - we don't have a master branch --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index ca2d4596b..2e2cdd2f0 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -21,7 +21,7 @@ pipeline { stage ('Deploy') { when { - branch "master" + branch "java-1.16" } steps { From ce78e43a5cafe0f6b55f5c09148dd18d4eb2df56 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:39:56 -0500 Subject: [PATCH 039/100] Attempt 5 --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 2e2cdd2f0..00eefa28e 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -37,7 +37,7 @@ pipeline { ) rtGradleRun ( usesPlugin: true, - tool: GRADLE_TOOL, + tool: gradle, rootDir: "/", buildFile: 'build.gradle', tasks: 'clean artifactoryPublish', From 0dec24d0c95e1f040fc25bd7d7d608533a407e6c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:44:30 -0500 Subject: [PATCH 040/100] Attempt 6 --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 00eefa28e..9bdf4963a 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -37,7 +37,7 @@ pipeline { ) rtGradleRun ( usesPlugin: true, - tool: gradle, + tool: 'Gradle 6', rootDir: "/", buildFile: 'build.gradle', tasks: 'clean artifactoryPublish', From 6c3c07b6a45c27d3bb1e74d3f9bb62006d52f6ea Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:51:39 -0500 Subject: [PATCH 041/100] Attempt 7 --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 9bdf4963a..2c82f17ad 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -38,7 +38,7 @@ pipeline { rtGradleRun ( usesPlugin: true, tool: 'Gradle 6', - rootDir: "/", + rootDir: "", buildFile: 'build.gradle', tasks: 'clean artifactoryPublish', deployerId: "GRADLE_DEPLOYER", From 373ae84d2db1b1b886df1e8dc5b28f103d90ba8e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:59:45 -0500 Subject: [PATCH 042/100] Attempt 8 --- bootstrap/fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0f8f35cbc..dea3bb122 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -3,6 +3,7 @@ plugins { id 'maven-publish' id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java' + id "com.jfrog.artifactory" } apply plugin: 'com.github.johnrengelman.shadow' From 6bf0c5d94c84077fd0eb73175a52454288316c01 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 14:04:38 -0500 Subject: [PATCH 043/100] Attempt 9 --- bootstrap/fabric/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index dea3bb122..946da0cca 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -3,7 +3,7 @@ plugins { id 'maven-publish' id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java' - id "com.jfrog.artifactory" + id "com.jfrog.artifactory" version '4.18.3' } apply plugin: 'com.github.johnrengelman.shadow' From fad2fc149cfe5069480f02589f8fe3bc3441f71c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 8 Jan 2021 14:26:53 -0500 Subject: [PATCH 044/100] Publish artifacts? Attempt 1 --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 2c82f17ad..2a2436547 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { tool: 'Gradle 6', rootDir: "", buildFile: 'build.gradle', - tasks: 'clean artifactoryPublish', + tasks: 'clean build artifactoryPublish', deployerId: "GRADLE_DEPLOYER", resolverId: "GRADLE_RESOLVER" ) From fd151d4e3a51aaf32e3a0470cf585a2be8b3af71 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 9 Jan 2021 11:41:37 -0500 Subject: [PATCH 045/100] Attempt 2 of trying to get a build out of this --- bootstrap/fabric/Jenkinsfile | 2 +- bootstrap/fabric/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 2a2436547..a027e87f0 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -36,7 +36,7 @@ pipeline { serverId: "opencollab-artifactory", ) rtGradleRun ( - usesPlugin: true, + usesPlugin: false, tool: 'Gradle 6', rootDir: "", buildFile: 'build.gradle', diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 946da0cca..8de36084e 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -3,7 +3,7 @@ plugins { id 'maven-publish' id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java' - id "com.jfrog.artifactory" version '4.18.3' + //id "com.jfrog.artifactory" version '4.18.3' } apply plugin: 'com.github.johnrengelman.shadow' From a5e0cab48a5ffcabeb7dba18f00e9f62419764de Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 9 Jan 2021 11:53:09 -0500 Subject: [PATCH 046/100] Clean up :) --- bootstrap/fabric/Jenkinsfile | 2 +- bootstrap/fabric/build.gradle | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index a027e87f0..f0a92dafa 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { tool: 'Gradle 6', rootDir: "", buildFile: 'build.gradle', - tasks: 'clean build artifactoryPublish', + tasks: 'build artifactoryPublish', deployerId: "GRADLE_DEPLOYER", resolverId: "GRADLE_RESOLVER" ) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 8de36084e..0f8f35cbc 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -3,7 +3,6 @@ plugins { id 'maven-publish' id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java' - //id "com.jfrog.artifactory" version '4.18.3' } apply plugin: 'com.github.johnrengelman.shadow' From 5fcf48e1c63387439394e07ccb452963d599c5c9 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 14 Jan 2021 00:07:23 +0000 Subject: [PATCH 047/100] Add skippable discord notifications to the build --- bootstrap/fabric/Jenkinsfile | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index f0a92dafa..9ad332239 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -4,9 +4,15 @@ pipeline { gradle 'Gradle 6' jdk 'Java 8' } + + parameters{ + booleanParam(defaultValue: false, description: 'Skip Discord notification', name: 'SKIP_DISCORD') + } + options { buildDiscarder(logRotator(artifactNumToKeepStr: '20')) } + stages { stage ('Build') { steps { @@ -85,8 +91,12 @@ pipeline { env.changes = message } deleteDir() - withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { - discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'Cloudburst Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK + script { + if(!params.SKIP_DISCORD) { + withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { + discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'Cloudburst Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK + } + } } } } From 49f02081e0c98bb473367366eed2895a8dbf4979 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 15 Jan 2021 14:27:55 -0500 Subject: [PATCH 048/100] Resolve https://github.com/CardboardPowered/cardboard/issues/139 --- bootstrap/fabric/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0f8f35cbc..751a5da4f 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -85,6 +85,10 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") + dependencies { + // https://github.com/CardboardPowered/cardboard/issues/139 + exclude(dependency('org.objectweb:asm:*')) + } } jar { From 24da65dcb5e588a23f2ec8487ef5e2e83a84b5c7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 15 Jan 2021 19:42:47 -0500 Subject: [PATCH 049/100] Apparently exclusion isn't working. Temporary fix --- bootstrap/fabric/build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 751a5da4f..72f561c7d 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -85,10 +85,8 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") - dependencies { - // https://github.com/CardboardPowered/cardboard/issues/139 - exclude(dependency('org.objectweb:asm:*')) - } + relocate("org.objectweb.asm", "org.geysermc.relocate.asm") + relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 } jar { From c3569093b637ac539320a65fcf0e2cf67f7bedc2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 21 Jan 2021 14:57:06 -0500 Subject: [PATCH 050/100] Update command handling --- .../platform/fabric/GeyserFabricMod.java | 5 +-- .../fabric/command/FabricCommandSender.java | 15 +++------ .../command/GeyserFabricCommandExecutor.java | 31 ++++++++++++------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 4f1eed1c9..32d383017 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -149,11 +149,12 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { // Start command building // Set just "geyser" as the help command LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") - .executes(new GeyserFabricCommandExecutor(connector, "help", !playerCommands.contains("help"))); + .executes(new GeyserFabricCommandExecutor(connector, connector.getCommandManager().getCommands().get("help"), + !playerCommands.contains("help"))); for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { // Register all subcommands as valid builder.then(net.minecraft.server.command.CommandManager.literal( - command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getKey(), + command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getValue(), !playerCommands.contains(command.getKey())))); } server.getCommandManager().getDispatcher().register(builder); diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index 3ec548143..d49a07625 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -25,8 +25,8 @@ package org.geysermc.platform.fabric.command; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.LiteralText; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; @@ -47,20 +47,15 @@ public class FabricCommandSender implements CommandSender { @Override public void sendMessage(String message) { - try { - source.getPlayer().sendMessage(new LiteralText(message), false); - } catch (CommandSyntaxException e) { // why + if (source.getEntity() instanceof ServerPlayerEntity) { + ((ServerPlayerEntity) source.getEntity()).sendMessage(new LiteralText(message), false); + } else { GeyserConnector.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); } } @Override public boolean isConsole() { - try { - source.getPlayer(); - return false; - } catch (CommandSyntaxException e) { - return true; - } + return !(source.getEntity() instanceof ServerPlayerEntity); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index 706ef9502..a8469364f 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -29,22 +29,24 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import net.minecraft.server.command.ServerCommandSource; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandExecutor; import org.geysermc.connector.command.GeyserCommand; +import org.geysermc.connector.common.ChatColor; +import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.GeyserFabricMod; -public class GeyserFabricCommandExecutor implements Command { +public class GeyserFabricCommandExecutor extends CommandExecutor implements Command { - private final String commandName; - private final GeyserConnector connector; + private final GeyserCommand command; /** * Whether the command requires an OP permission level of 2 or greater */ private final boolean requiresPermission; - public GeyserFabricCommandExecutor(GeyserConnector connector, String commandName, boolean requiresPermission) { - this.commandName = commandName; - this.connector = connector; + public GeyserFabricCommandExecutor(GeyserConnector connector, GeyserCommand command, boolean requiresPermission) { + super(connector); + this.command = command; this.requiresPermission = requiresPermission; } @@ -56,14 +58,19 @@ public class GeyserFabricCommandExecutor implements Command sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } - if (this.commandName.equals("reload")) { + if (this.command.getName().equals("reload")) { GeyserFabricMod.getInstance().setReloading(true); } - getCommand(commandName).execute(sender, new String[0]); + + GeyserSession session = null; + if (command.isBedrockOnly()) { + session = getGeyserSession(sender); + if (session == null) { + sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + return 0; + } + } + command.execute(session, sender, new String[0]); return 0; } - - private GeyserCommand getCommand(String label) { - return connector.getCommandManager().getCommands().get(label); - } } From 2020881799a7185d3f42c8de7bc8f5ede7ae4dfc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 4 Feb 2021 10:17:06 -0500 Subject: [PATCH 051/100] Add support for new metric --- .../java/org/geysermc/platform/fabric/GeyserFabricMod.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 32d383017..5e156cfec 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -48,6 +48,7 @@ import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileOutputStream; @@ -201,6 +202,11 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return new GeyserFabricDumpInfo(server); } + @Override + public String getMinecraftServerVersion() { + return this.server.getVersion(); + } + private File fileOrCopiedFromResource(File file, String name) throws IOException { if (!file.exists()) { //noinspection ResultOfMethodCallIgnored From 31a7b798f1eed7d129566b936a3fe7faf4f22837 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 5 Feb 2021 12:29:15 -0500 Subject: [PATCH 052/100] Remove Lombok --- bootstrap/fabric/build.gradle | 3 --- .../platform/fabric/GeyserFabricDumpInfo.java | 13 ++++++++-- .../platform/fabric/GeyserFabricMod.java | 12 ++++++--- .../fabric/GeyserFabricPermissions.java | 5 ++-- .../org/geysermc/platform/fabric/ModInfo.java | 25 ++++++++++++++----- .../mixin/client/IntegratedServerMixin.java | 1 - .../server/MinecraftDedicatedServerMixin.java | 4 +-- 7 files changed, 42 insertions(+), 21 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 72f561c7d..0e8c2d181 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -29,9 +29,6 @@ dependencies { implementation 'org.geysermc:connector:1.2.0-SNAPSHOT' shadow 'org.geysermc:connector:1.2.0-SNAPSHOT' - - compileOnly 'org.projectlombok:lombok:1.18.4' - annotationProcessor 'org.projectlombok:lombok:1.18.4' } repositories { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java index 1b9d68a9c..f6a7bf9fa 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -25,7 +25,6 @@ package org.geysermc.platform.fabric; -import lombok.Getter; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.server.MinecraftServer; @@ -35,7 +34,6 @@ import org.geysermc.connector.dump.BootstrapDumpInfo; import java.util.ArrayList; import java.util.List; -@Getter public class GeyserFabricDumpInfo extends BootstrapDumpInfo { private String serverIP; @@ -57,4 +55,15 @@ public class GeyserFabricDumpInfo extends BootstrapDumpInfo { } } + public String getServerIP() { + return this.serverIP; + } + + public int getServerPort() { + return this.serverPort; + } + + public List getMods() { + return this.mods; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 5e156cfec..3ffff5455 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -26,7 +26,6 @@ package org.geysermc.platform.fabric; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import lombok.Setter; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -48,20 +47,21 @@ import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private static GeyserFabricMod instance; - @Setter private boolean reloading; private GeyserConnector connector; @@ -207,6 +207,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return this.server.getVersion(); } + public void setReloading(boolean reloading) { + this.reloading = reloading; + } + private File fileOrCopiedFromResource(File file, String name) throws IOException { if (!file.exists()) { //noinspection ResultOfMethodCallIgnored diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java index 51a7cb2e4..1a446bca6 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java @@ -27,7 +27,6 @@ package org.geysermc.platform.fabric; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; /** * A class outline of the permissions.yml file @@ -35,8 +34,10 @@ import lombok.Getter; @JsonIgnoreProperties(ignoreUnknown = true) public class GeyserFabricPermissions { - @Getter @JsonProperty("commands") private String[] commands; + public String[] getCommands() { + return this.commands; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java index 159678766..da753c44f 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java @@ -25,7 +25,6 @@ package org.geysermc.platform.fabric; -import lombok.Getter; import net.fabricmc.loader.api.ModContainer; import java.util.ArrayList; @@ -34,13 +33,12 @@ import java.util.List; /** * A wrapper for Fabric mod information to be presented in a Geyser dump */ -@Getter public class ModInfo { - private String name; - private String id; - private String version; - private List authors; + private final String name; + private final String id; + private final String version; + private final List authors; public ModInfo(ModContainer mod) { this.name = mod.getMetadata().getName(); @@ -50,4 +48,19 @@ public class ModInfo { this.version = mod.getMetadata().getVersion().getFriendlyString(); } + public String getName() { + return this.name; + } + + public String getId() { + return this.id; + } + + public String getVersion() { + return this.version; + } + + public List getAuthors() { + return this.authors; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java index 5415a9d3a..0a3f17f68 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -32,7 +32,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.text.LiteralText; import net.minecraft.world.GameMode; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.GeyserServerPortGetter; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java index eec6af74f..f5e9a121d 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -32,7 +32,6 @@ import net.minecraft.resource.ResourcePackManager; import net.minecraft.resource.ServerResourceManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.WorldGenerationProgressListenerFactory; -import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.util.UserCache; import net.minecraft.util.registry.DynamicRegistryManager; @@ -44,8 +43,7 @@ import org.spongepowered.asm.mixin.Mixin; import java.net.Proxy; @Mixin(MinecraftDedicatedServer.class) -public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter -{ +public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter { // Constructor to compile public MinecraftDedicatedServerMixin(Thread thread, DynamicRegistryManager.Impl impl, LevelStorage.Session session, SaveProperties saveProperties, ResourcePackManager resourcePackManager, Proxy proxy, DataFixer dataFixer, ServerResourceManager serverResourceManager, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { super(thread, impl, session, saveProperties, resourcePackManager, proxy, dataFixer, serverResourceManager, minecraftSessionService, gameProfileRepository, userCache, worldGenerationProgressListenerFactory); From e8b2bff951383494a2ff6cf4d2b0c282e0a239a1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 5 Feb 2021 12:54:35 -0500 Subject: [PATCH 053/100] Add platform and environment type to dump --- .../platform/fabric/GeyserFabricDumpInfo.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java index f6a7bf9fa..26979d6da 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -25,6 +25,7 @@ package org.geysermc.platform.fabric; +import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.server.MinecraftServer; @@ -34,14 +35,25 @@ import org.geysermc.connector.dump.BootstrapDumpInfo; import java.util.ArrayList; import java.util.List; +@SuppressWarnings("unused") // The way that the dump renders makes them used public class GeyserFabricDumpInfo extends BootstrapDumpInfo { - private String serverIP; - private int serverPort; - private List mods; + private String platformVersion = null; + private final EnvType environmentType; + + private final String serverIP; + private final int serverPort; + private final List mods; public GeyserFabricDumpInfo(MinecraftServer server) { super(); + for (ModContainer modContainer : FabricLoader.getInstance().getAllMods()) { + if (modContainer.getMetadata().getId().equals("fabricloader")) { + this.platformVersion = modContainer.getMetadata().getVersion().getFriendlyString(); + break; + } + } + this.environmentType = FabricLoader.getInstance().getEnvironmentType(); if (AsteriskSerializer.showSensitive || (server.getServerIp() == null || server.getServerIp().equals("") || server.getServerIp().equals("0.0.0.0"))) { this.serverIP = server.getServerIp(); } else { @@ -55,6 +67,14 @@ public class GeyserFabricDumpInfo extends BootstrapDumpInfo { } } + public String getPlatformVersion() { + return platformVersion; + } + + public EnvType getEnvironmentType() { + return environmentType; + } + public String getServerIP() { return this.serverIP; } From 17e3895b8279dae0973b95fe8609c2d2ea2f4268 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 14 Mar 2021 13:33:53 -0400 Subject: [PATCH 054/100] Implement lectern direct access (better lecterns like Geyser-Spigot) --- .../platform/fabric/GeyserFabricMod.java | 10 ++ .../world/GeyserFabricWorldManager.java | 123 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 3ffff5455..7c87b5ede 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -41,12 +41,14 @@ import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; +import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; +import org.geysermc.platform.fabric.world.GeyserFabricWorldManager; import java.io.File; import java.io.FileOutputStream; @@ -73,6 +75,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private GeyserFabricConfiguration geyserConfig; private GeyserFabricLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; + private WorldManager geyserWorldManager; @Override public void onInitialize() { @@ -147,6 +150,8 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { this.geyserCommandManager = new GeyserFabricCommandManager(connector); + this.geyserWorldManager = new GeyserFabricWorldManager(server); + // Start command building // Set just "geyser" as the help command LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") @@ -192,6 +197,11 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return geyserPingPassthrough; } + @Override + public WorldManager getWorldManager() { + return geyserWorldManager; + } + @Override public Path getConfigFolder() { return dataFolder; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java new file mode 100644 index 000000000..9e3afbbcc --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 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.platform.fabric.world; + +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.LecternBlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.WritableBookItem; +import net.minecraft.item.WrittenBookItem; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; +import org.geysermc.connector.network.translators.world.GeyserWorldManager; +import org.geysermc.connector.utils.BlockEntityUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class GeyserFabricWorldManager extends GeyserWorldManager { + private final MinecraftServer server; + + public GeyserFabricWorldManager(MinecraftServer server) { + this.server = server; + } + + @Override + public boolean shouldExpectLecternHandled() { + return true; + } + + @Override + public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { + Runnable lecternGet = () -> { + // Mostly a reimplementation of Spigot lectern support + PlayerEntity player = server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + if (player != null) { + BlockEntity blockEntity = player.world.getBlockEntity(new BlockPos(x, y, z)); + if (!(blockEntity instanceof LecternBlockEntity)) { + return; + } + + LecternBlockEntity lectern = (LecternBlockEntity) blockEntity; + if (!lectern.hasBook()) { + if (!isChunkLoad) { + BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); + } + return; + } + + ItemStack book = lectern.getBook(); + int pageCount = WrittenBookItem.getPageCount(book); + boolean hasBookPages = pageCount > 0; + NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); + lecternTag.putInt("page", lectern.getCurrentPage() / 2); + NbtMapBuilder bookTag = NbtMap.builder() + .putByte("Count", (byte) book.getCount()) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:writable_book"); + List pages = new ArrayList<>(hasBookPages ? pageCount : 1); + if (hasBookPages && WritableBookItem.isValid(book.getTag())) { + ListTag listTag = book.getTag().getList("pages", 8); + + for (int i = 0; i < listTag.size(); i++) { + String page = listTag.getString(i); + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", page); + pages.add(pageBuilder.build()); + } + } else { + // Empty page + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", ""); + pages.add(pageBuilder.build()); + } + + bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); + lecternTag.putCompound("book", bookTag.build()); + NbtMap blockEntityTag = lecternTag.build(); + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); + } + }; + if (isChunkLoad) { + // Hacky hacks to allow lectern loading to be delayed + session.getConnector().getGeneralThreadPool().schedule(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS); + } else { + server.execute(lecternGet); + } + return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); + } +} From 5418b9e26307d8a2a915e279f92ef021eadc883c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 1 Apr 2021 20:07:32 -0400 Subject: [PATCH 055/100] Update for Floodgate 2.0 --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- .../fabric/GeyserFabricConfiguration.java | 17 ++++++++++++++++- .../platform/fabric/GeyserFabricMod.java | 19 +++++++++++++++---- .../fabric/src/main/resources/fabric.mod.json | 2 +- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0e8c2d181..cb63756b2 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.2.0-SNAPSHOT' - shadow 'org.geysermc:connector:1.2.0-SNAPSHOT' + implementation 'org.geysermc:connector:1.3.0-SNAPSHOT' + shadow 'org.geysermc:connector:1.3.0-SNAPSHOT' } repositories { diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 7fe0d5d14..43be1e478 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.16.3 yarn_mappings=1.16.3+build.28 loader_version=0.10.1+build.209 # Mod Properties -mod_version=1.0-SNAPSHOT +mod_version=1.3.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java index 9f843693a..f3b446760 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java @@ -25,13 +25,28 @@ package org.geysermc.platform.fabric; +import com.fasterxml.jackson.annotation.JsonIgnore; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import org.geysermc.connector.FloodgateKeyLoader; import org.geysermc.connector.configuration.GeyserJacksonConfiguration; import java.nio.file.Path; +import java.util.Optional; public class GeyserFabricConfiguration extends GeyserJacksonConfiguration { + @JsonIgnore + private Path floodgateKeyPath; + + public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) { + Path geyserDataFolder = geyser.getConfigFolder(); + Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate"); + + floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger()); + } + @Override public Path getFloodgateKeyPath() { - return null; + return floodgateKeyPath; } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 7c87b5ede..cbcc452bf 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -30,6 +30,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import org.apache.logging.log4j.LogManager; @@ -55,10 +56,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @@ -144,6 +142,19 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); } + Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate"); + boolean floodgatePresent = floodgate.isPresent(); + if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !floodgatePresent) { + geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + return; + } else if (geyserConfig.isAutoconfiguredRemote() && floodgatePresent) { + // Floodgate installed means that the user wants Floodgate authentication + geyserLogger.debug("Auto-setting to Floodgate authentication."); + geyserConfig.getRemote().setAuthType("floodgate"); + } + + geyserConfig.loadFloodgate(this, floodgate.orElse(null)); + this.connector = GeyserConnector.start(PlatformType.FABRIC, this); this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 89cbd12b5..ceb37daf3 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -12,7 +12,7 @@ "repo": "https://github.com/GeyserMC/Geyser-Fabric" }, "license": "MIT", - "icon": "assets/fabric/icon.png", + "icon": "assets/geyser-fabric/icon.png", "environment": "*", "entrypoints": { "main": [ From 88cb680c3f07d79aff2bdc5dd22b2c896ebe6971 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 6 Apr 2021 00:29:00 -0400 Subject: [PATCH 056/100] Update for 1.16.220 --- bootstrap/fabric/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0e8c2d181..ca7dbfc0c 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.2.0-SNAPSHOT' - shadow 'org.geysermc:connector:1.2.0-SNAPSHOT' + implementation 'org.geysermc:connector:1.2.1-SNAPSHOT' + shadow 'org.geysermc:connector:1.2.1-SNAPSHOT' } repositories { From d07a69be8940d14d470fb2f8f91d2b461da27b9a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Jun 2021 09:58:17 -0400 Subject: [PATCH 057/100] Return on config fail --- .../main/java/org/geysermc/platform/fabric/GeyserFabricMod.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 7c87b5ede..ac9330ddc 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -104,6 +104,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { } catch (IOException ex) { LogManager.getLogger("geyser-fabric").error(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); + return; } this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode()); From 28fb957fd98bc53ff3cd0929c9322badfdbfb84d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:33:54 -0400 Subject: [PATCH 058/100] Update for 1.17-rc1 and use Java 16 --- bootstrap/fabric/Jenkinsfile | 7 +++++-- bootstrap/fabric/build.gradle | 13 ++++--------- bootstrap/fabric/gradle.properties | 8 ++++---- .../fabric/gradle/wrapper/gradle-wrapper.properties | 2 +- .../fabric/world/GeyserFabricWorldManager.java | 4 ++-- bootstrap/fabric/src/main/resources/fabric.mod.json | 4 ++-- .../src/main/resources/geyser-fabric.mixins.json | 2 +- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 9ad332239..c688c5a2c 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -2,7 +2,7 @@ pipeline { agent any tools { gradle 'Gradle 6' - jdk 'Java 8' + jdk 'Java 16' } parameters{ @@ -27,7 +27,10 @@ pipeline { stage ('Deploy') { when { - branch "java-1.16" + anyOf { + branch "java-1.16" + branch "java-1.17" + } } steps { diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index cb63756b2..b3c02b2d7 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.5-SNAPSHOT' + id 'fabric-loom' version '0.8-SNAPSHOT' id 'maven-publish' id 'com.github.johnrengelman.shadow' version '6.1.0' id 'java' @@ -8,8 +8,8 @@ plugins { apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'java' -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 +sourceCompatibility = JavaVersion.VERSION_16 +targetCompatibility = JavaVersion.VERSION_16 archivesBaseName = project.archives_base_name version = project.mod_version @@ -54,14 +54,9 @@ repositories { processResources { inputs.property "version", project.version - from(sourceSets.main.resources.srcDirs) { - include "fabric.mod.json" + filesMatching("fabric.mod.json") { expand "version": project.version } - - from(sourceSets.main.resources.srcDirs) { - exclude "fabric.mod.json" - } } // ensure that the encoding is set to UTF-8, no matter what the system default is diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 43be1e478..4d3b4cf87 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.16.3 -yarn_mappings=1.16.3+build.28 -loader_version=0.10.1+build.209 +minecraft_version=1.17-rc1 +yarn_mappings=1.17-rc1+build.5 +loader_version=0.11.3 # Mod Properties mod_version=1.3.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.23.0+build.410-1.16 +fabric_version=0.34.9+1.17 diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties index bb8b2fc26..0f80bbf51 100644 --- a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties +++ b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index 9e3afbbcc..63f4b638b 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -35,7 +35,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.WritableBookItem; import net.minecraft.item.WrittenBookItem; -import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtList; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import org.geysermc.connector.network.session.GeyserSession; @@ -89,7 +89,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { .putString("Name", "minecraft:writable_book"); List pages = new ArrayList<>(hasBookPages ? pageCount : 1); if (hasBookPages && WritableBookItem.isValid(book.getTag())) { - ListTag listTag = book.getTag().getList("pages", 8); + NbtList listTag = book.getTag().getList("pages", 8); for (int i = 0; i < listTag.size(); i++) { String page = listTag.getString(i); diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index ceb37daf3..eaec51a21 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -23,8 +23,8 @@ "geyser-fabric.mixins.json" ], "depends": { - "fabricloader": ">=0.10.1+build.209", + "fabricloader": ">=0.11.3", "fabric": "*", - "minecraft": ">=1.16.3" + "minecraft": "1.17.x" } } diff --git a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json index 3965f9781..6081bee93 100644 --- a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json +++ b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json @@ -1,7 +1,7 @@ { "required": true, "package": "org.geysermc.platform.fabric.mixin", - "compatibilityLevel": "JAVA_8", + "compatibilityLevel": "JAVA_16", "client": [ "client.IntegratedServerMixin" ], From d08cd542d09622095b3812dd6d65acb58acafdd0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:35:43 -0400 Subject: [PATCH 059/100] Use local Gradle/Gradle 7 --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index c688c5a2c..e8821f3d6 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -16,7 +16,7 @@ pipeline { stages { stage ('Build') { steps { - sh 'gradle clean build --refresh-dependencies' + sh './gradlew clean build --refresh-dependencies' } post { success { From d64038d311c1ec62c7b5681ab5fe5bafc6ec5f1d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:42:42 -0400 Subject: [PATCH 060/100] Well that didn't commit ok --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index e8821f3d6..7dc757e70 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -1,7 +1,7 @@ pipeline { agent any tools { - gradle 'Gradle 6' + gradle 'Gradle 7' jdk 'Java 16' } From f0ba0dbf4c031dbb2accf2c558b1322edde9be2f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Jun 2021 17:36:25 -0400 Subject: [PATCH 061/100] ... --- bootstrap/fabric/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 7dc757e70..24a90026a 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -46,7 +46,7 @@ pipeline { ) rtGradleRun ( usesPlugin: false, - tool: 'Gradle 6', + tool: 'Gradle 7', rootDir: "", buildFile: 'build.gradle', tasks: 'build artifactoryPublish', From 2092a75e429fa5f6b3d49113d6f8c3fc484369a3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 8 Jun 2021 14:02:19 -0400 Subject: [PATCH 062/100] Bump to use Geyser 1.4.0-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index b3c02b2d7..0fa9183af 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.3.0-SNAPSHOT' - shadow 'org.geysermc:connector:1.3.0-SNAPSHOT' + implementation 'org.geysermc:connector:1.4.0-SNAPSHOT' + shadow 'org.geysermc:connector:1.4.0-SNAPSHOT' } repositories { From b08ad206cafc1e5dec3a3a585e94768445276b57 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 10 Jun 2021 10:02:59 -0400 Subject: [PATCH 063/100] Bump version to 1.4.0-SNAPSHOT --- bootstrap/fabric/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 4d3b4cf87..699017989 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.17-rc1 yarn_mappings=1.17-rc1+build.5 loader_version=0.11.3 # Mod Properties -mod_version=1.3.0-SNAPSHOT +mod_version=1.4.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From fa8ddde9b454df6dddc5313e05076190291a43f7 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 2 Jul 2021 14:50:37 +0100 Subject: [PATCH 064/100] Update build badge --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index d50255b1f..fee65e3e1 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -2,7 +2,7 @@ [![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) -Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.16/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) +Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) From 2c1fbc544a02cd0834819807157d3b7ab26808cf Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 2 Jul 2021 14:52:45 +0100 Subject: [PATCH 065/100] Fix download link --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index fee65e3e1..26cb55da7 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -2,7 +2,7 @@ [![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) -Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/lastSuccessfulBuild/artifact/build/libs/Geyser-Fabric-1.0-SNAPSHOT.jar) +Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/java-1.17/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) From c220e5428c409e1bbedf242d0e48011026f7699a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 5 Jul 2021 22:28:41 -0400 Subject: [PATCH 066/100] Relocate Google libraries --- bootstrap/fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0fa9183af..cc11f556f 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -79,6 +79,7 @@ shadowJar { relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") relocate("org.objectweb.asm", "org.geysermc.relocate.asm") relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 + relocate("com.google", "org.geysermc.relocate.google") } jar { From 7660ebb48b2d2bfb61e1bb799a936a8f4cfd1e83 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 12 Jul 2021 21:55:42 -0400 Subject: [PATCH 067/100] Update to the latest Geyser version --- bootstrap/fabric/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index cc11f556f..65dccb9a1 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.4.0-SNAPSHOT' - shadow 'org.geysermc:connector:1.4.0-SNAPSHOT' + implementation 'org.geysermc:connector:1.4.1-SNAPSHOT' + shadow 'org.geysermc:connector:1.4.1-SNAPSHOT' } repositories { From fcbd90c4d608d7731b557bfbe888aea362e9e9aa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 16 Jul 2021 10:53:48 -0400 Subject: [PATCH 068/100] Require 1.17.1 or greater --- bootstrap/fabric/gradle.properties | 8 ++++---- .../fabric/world/GeyserFabricWorldManager.java | 7 +++---- .../resources/assets/geyser-fabric/icon.png | Bin 0 -> 115461 bytes .../fabric/src/main/resources/fabric.mod.json | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) create mode 100644 bootstrap/fabric/src/main/resources/assets/geyser-fabric/icon.png diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 699017989..fbbf18cd3 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.17-rc1 -yarn_mappings=1.17-rc1+build.5 -loader_version=0.11.3 +minecraft_version=1.17.1 +yarn_mappings=1.17.1+build.14 +loader_version=0.11.6 # Mod Properties mod_version=1.4.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.34.9+1.17 +fabric_version=0.37.0+1.17 diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index 63f4b638b..dd0d629c8 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -66,11 +66,10 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { PlayerEntity player = server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); if (player != null) { BlockEntity blockEntity = player.world.getBlockEntity(new BlockPos(x, y, z)); - if (!(blockEntity instanceof LecternBlockEntity)) { + if (!(blockEntity instanceof LecternBlockEntity lectern)) { return; } - LecternBlockEntity lectern = (LecternBlockEntity) blockEntity; if (!lectern.hasBook()) { if (!isChunkLoad) { BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); @@ -88,8 +87,8 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { .putShort("Damage", (short) 0) .putString("Name", "minecraft:writable_book"); List pages = new ArrayList<>(hasBookPages ? pageCount : 1); - if (hasBookPages && WritableBookItem.isValid(book.getTag())) { - NbtList listTag = book.getTag().getList("pages", 8); + if (hasBookPages && WritableBookItem.isValid(book.getNbt())) { + NbtList listTag = book.getNbt().getList("pages", 8); for (int i = 0; i < listTag.size(); i++) { String page = listTag.getString(i); diff --git a/bootstrap/fabric/src/main/resources/assets/geyser-fabric/icon.png b/bootstrap/fabric/src/main/resources/assets/geyser-fabric/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4e6a38a787f0ed02a93b2580b5be0e838ffefea3 GIT binary patch literal 115461 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�? zRfJPfpcHn15-_1>hYBhI+)L+MD!l>aks|0YJ65}chvV_s6~#%(8a{(&X|?~^9gA3o z_KpmNm%b5_b-~>`cKYMZ0N#h`-l|~3R2(CNIC>ssu!*MzoeN~}39dp;c5#@=MGW@V zWZ4l4;B>f)wl(o}iWed*tY!OQguFL_XDS}+YJMuz;0EfN{S*NC88h*Yzhd{f^;fff|T?Ih?D{fNN?$b7v9@(-`91Yuk$=hg42jX6=dI)9Yj>)UGt>4(?15g?$GU~$E}B2 z!57j~%npc$q2gO-=}ZT#Ml0R9p5VpTGBVeOTtRwcJ+wImybo4QB6m(deD|=^+c52r zGL<)@vM8}d(Q*KU^VG>MueD=kg#PPD_l67p*m<$R!mwEy{WSc}h19E8wZe-eCvv}% z_Gcs8EHdunI^*Oe`96I4l-N>Kc2i8ORs}(lU;4^2hQS&_X7Z*5E+K&I*c`I`({D9I zn2J{hj21zyd_W$y1Qt4;^#1Vno5lSEA3C@;pu$R)AG%()x-mgFM6mLHs{mVb((xka zKwqV;kP}piHkshQD>>S*w+G97Ov~U*@r*Zw!B;1YBUAsv%V)l{Pq9%7CaY!FO^|o} zy4RQ+MI%I45d(I-%Rwu66aZkM#ssY9v_77aNv;QF|IHSn>&+8>SSOQRwD7qJPClBW zyx^UH=HmzYPk816>tf^Jo1kADkK)%g)uKZ6E`j}iG-8YrKlNYc^RdwoaZ0t^vRl0M zs>rkNc3)0^o_fVuzrtObr=5cEL+*Rq%6Fv0=X2B+7#Vv252ePun812{RZ&zzbV~x- z;fPqxF4->;Q6$O}yy>y)9mwpvM|+8_pUMX!dJAqgh$-6kEL=MtFvQVE9xfbQ(?pl# zxE=&Xj&5qCmRv;}ligkx{n6d0Tp_5o!wy6~xFTa`xmrx@a*Uz%8<&&9JbB=F0;nw$ z4e}+nj&uIxCX@H&be{KpCF{2R(|3B=Yi4Y1-D&Z)63Q-o(aG{{Gq90{e4KWxVFoIf zXiyM0++;r{)(jSLZ=zL5u?mF-0uY*Y-&5fQ9|}d7mYP$TsC7Ri#e97IeyUR1FrFJ9 z_BKk8n{##8^+e}$)|rnn#>rn8nUi{H<^T6tB;3OxQb+=acLX1P`2?E}za zf7P*5b?ck2P<*IVBIS@~hPi?#sTyAbNA{a9`x0>aLT1nyr8RO`z{j|$oBsBm?v5gU z^R)^E!^vrPAk*EPKPC^$OH@CPQpQh0@1!GC!AZBl112 zO!I35g32a+VLg-X{HJ<#hF!}laY%Hn_5}O@KgXnaJ82a2gU*IiuXM86+d%=^Ba^Zu zp6EgJu>k(O5@zKJMB}U@) zOrVnj4rGRkj}nPtTtJ1CH6C{A^dLa?+DqFL(D_I61wY^8wC;(G=OYj<6&s6=8Y3du zc&i&cI5FBjYS&2`4RELp)sjFq2>WeLEyC8Nkiz!$Nr4^e*CzEOJ?$um`4t16&DyC@ zdf3u}j{L&=AHMyaO}oh{4{v;$lQHf5m?jwFP|Mt}t9OBm|DdPx4+tdap_O64rni7# zGF?$WzUpY`)O_T1LW$ zC-GJY4Qiirw~{@Cdysg4L5Zu1z5OUmmhGAmEqYv(rTRzGFg`-VbRdS*dnv`?u}N8Y z`^gn%=G3v53!kskBR=$m>#Hv?B#X~FW0R&L>mAjz&rreVn7zZ0?)Zmqlv?%sv33Zl zekX1yj9`ewt^&9e9@6w}7c&^wfV^&4i)Qxb)a2Nn$#2CD5d$;sCi);>P5@fi{pBHE zcVDANu@Gh@pwt%wUM<`E(lR$P<(rD%-6{B|w(={~=4aLy)*A*dw+-ylAWXrPno`@% zlVHxDpwD8!$iJ+qg9>J5$>mLZrM#&0`t;ja#jEdsIj1gmey7H&hMJ6~{oRTI=l%ib z;>y;NC<_G>Q5{OwBl)h~vC!77M-_8kragc=6an>F(8Z`1(CsDnEG36)w99DAhbp(< z5pPd;(>l!duM>j-_kdv~oW5~$Mig+b)$o8v@&5AMM!h4{6J6FUkdJ$I{7cNM0+m6I zv$l+z8X21;n>HtaXU=VzqkOl(-S2d*7HQ77ZWwu9FIbLt$7p}>wtH$4DH{#nYqfE7 z{@KYoY5t!K$=dRRg%O1Z6NaVfd&3z&^*l5wYu2q}B5A6s)27koh4=qt=Uex1Zq3Z) z9SpynsP4b-odh0lVf!Y_iuV==*b$mI;5MlXZFN+!pYzYB4wV|y-@NYz`@aZC^LfT` zo>_2=*ndS8FYqz6-?`+kZTkbfx7Q3-rjDhvoB9g5?@8FChLtAaH=D3(pKjvmbobG( z*3?Z~_RR2NMKpM8|RvdI$W087dBEVEp$~*K^oifJ_bSIxqdbo7P2Q z8>*j2PtqkxdUhn=$(Zebi}^~^=?vD?xzyhP;?f9%3W9BE`{SGb8IvRi^O*yjR<7Gx zNd}}cg(yvR@VO^~Hg||Z$u^O7VlOp`Di?F@BWbP^T7#akdrS`M2{w9AOhsCfD2XNh z;B@P<;UMcQ)B%rB#+7lXjXrH_9wuG7POY}gB4Up>z+Q|l=?ZsqoDlnNDun??4`Ms| ziLjpj>VF!a;~nnz-C}Xt-2gMJQd;i6to*PJX@e3wlxwxCe%& zp;uhX$`}9+$A!l?<;@;2S;;+Omi&QJZ7m4xU_Q1NU_^cQBDrInF#gQCWzl=aCaZgZ z*19>0R1KUO8ex9~4)tl#rm4`P2-C{A)SWlaZvbSu=_DQS*g($P+zK zf1`nv47c5eOzOL7gWmeYKVYVjyflwaYzMT}P~Jkx8i(X7!|Cv%JCY=;vRCx+xwSSq za@T!cmN;jNGk>_d*Ue4dG@AY2p&i3UwnF(p|=cXDfZ={_xS zSs&R3zLAtdUnXKAs;&18l;`?A1&`!E8=fTwwz`%LKozQ|YdmKM=SE6QVvvKYE$7FJ zM%Bsxq+b{^Lnid6(VF%Upv6T0mX$Hy_B8(Nx6ob)5P#QMXPqe;9xW+I#{bUS(mLGW z3|2MT&Wf|sUQcQ7h!=!0nGS@LktA%nB_B<<|HonP5vVOjskviPD zf6B+5%**Z-z>OOebsD=7%SY8ltr264Ptj|NN-KbEKP8epmyl=I+Pi9fdg}Cn^yQE4{iiT`$ymoFEFS-KMVWSQkao% zC2ceYmA-i!;<1waGkw4-Y4pmCjN)7qbQxGrxY=jFa%_wR;Xs$2^Y3IDSWxy}f;u}* z6M=foZy`ylYIRxrkJD7i-xrN~U2f{A<~%z+vMr^c7kf)~#Wc26Th7u@odw{n4jkgL zFDt)gN8EG-m(W!Jh{?70)u1vvs#9x8K|$tci%4v!qD-CZP_FpWu(;KPwXI7yrb(0W zLo#(XnF-z)8G&s(dqK22T%rMQYrMm#T9(J7yk79 zfWR`S#(P4ODm#b z76g7KH?d_hQ?|Ow&pUZFter%6H;<%s!D_cB?fojiV5Za>9gxM$M^x8cvEyT%teCKId3itVHwh@?*mD?QbM|f2ZjkM4V7L#xM8LTQ`-7Uqc zWJ@d|2kqz-CV@t9$W5*AIM~OlXX=gRT$r6>wZ>|Z*kN(&J}DHn1fANW8P1HtNO?r1 zhv>xasQ?MC)jF@#ht4hZ{&u?NAj`YQNxZ)nzeN~qa#C5APZ|tt^wLq#pU(Ns4Co_> zZP>#wHuKb{j^bg)adab%fTX=dl}7vNXZeDdp~T48iK;Nz%RISd_RI_8S?_1i8ReI{ z`vMYutVBM3ZnMV%*7DScn+Iulz^F0BB9a;trdhJ#6u*R$b|Ib~bz2|cC#-RRgCh3( z+?gu;kH5y7c&PHjMa+UOnA<;9ufO7|3HW&1?-*<)PWdavCFSyqEIIzJ$w*H^z&hwm zuQ0rA%;b35#^$k{4-JgiWWdLcPY%|8PE)bh$(prE#OVt1&Im>bIXEonXgYxivW}j( z&kiG3QZjhz#L26!{AW@U6`%ZaTAZ0)k<`I}9SfW->=Sp)nT1kqzK(Fmu!u~UY$RQI zX6tw$V>lX_71u-CKRLW5^>6)b$9+P%34VE3c!$rOdoXYd@`&fD$Ai$ejg8WVAshX9(1xrOaIz7y zI~%>LuCvh;!vS5~t8O=624r3%{}cywrdy|~g^&mm-$M_{la&D~K+RVO7x$tLEbr#v zSsB;;{owb49}T6$#lr-$J~5*diN1vVZt%s0C>u#cz_Eyv0QeW>k}z%=x!%k|RjYp-tVyQ$gY6Qh&i;BsOM9(}ys-(i(uVjEBB2W3eHXHx^gIaWc zhSBK!8+8oVH$i2*g`bA##R)!$c|5`jym2%+TB+u9amWlYMCla2P?)JXC8D}dG+p#* zSHBl~NBps7f}?3m}RUHzECP+1dvx*Pg_nY0tmJXT$cp z+t93d*O22em|S7-;c$x9WLJgGGfxz43e)q|H%yLiXu>v!rnm~iBtPl&9Pb7w-nBS= z@Up<_-WCe&%Z>9dZ@v_Jgz(v!d{P;rP!Sx+6!|`WoDPV!2(K&0Z;~$#Rv&L|W0Cl? zaQC>Oh_^TUAD7MI&R?O|`?Nqixn?&#t~rItQl;zz!U?n}@_|x=BFNSM9_oXU{Vtcv z-`At9SMt23%TyYzW{DR=1W}QBxxwCisavM0Y#JYIlE#ZxfEeY|P320d7iOaSn`RvLvC7^zbvaE{Cv z+IWJ9m`d;Qo9Mz$L028Ee@P$UQ{FoVN6yiJxbixIrz%hd$|>se9XCM{eZlOy{$z!i zu3mP@&~~*9u4GS}Iq^|`s1f+#DSwb3)?vX&45fpa)VX?qWO&m;fHsk5DW*e)*~^Vj z@2FqANRSnHZ$w%Fk~()Wk3dfHqK;*&jhxsq>~WwSEw*<5zk(R*M{h_&cATuBNH2=m zw#GQoxNwdTmbsq!JuvM_?rf9v}z4F=uaD}p0kqUNk7 zsu4Jo@K-f7C_d9Ax%7r^pxL&R5NNG^b#i~708t}cUx0<9y>x#S~GrMrpBwTln+gZ8%+ z?{ra$T2%t*QfR-ZG0_D|!}9+|@EQcvtO#7Xp4|Ttc!R~L3nyDv=G$dx5P!$~hwt52 zHA>G%ceI8%bd)z3(vEGL%x`q9-6xny7S=-*EL#AOuFj)3{6^4$pPfglGXg2=eK(pF zT|g0I(VW)*v3^G-lXfF+9^Uq3%*;1LkJ)O*20s^SSbrodi0lr(+7lZVx-R{J8bjnM?-~}_F71E3x27<}kp|YMlV;rGe_wL#8OwFW-|^N9LSbpY_MG-rX}vu#NVT-h7}a@}Yv zkv~j@FPT)jR&Rgx;0gNJN+XurMZ&kk-KC>V={67E*Ze;LyXAV@1sM`D_^pMKG4Gmt zu@)QhksbDKupl=6bLQr7ufixA=Zt0-AvVQEqVX*l4Zkyp%NnKCGMzb*jlF@`clV3@ zYcM=`xs|z*Lmug&(N|Uf=S!atw#6pqmcqdWhTlBcpPa{k+i}4rdt5!6OAz(rr>c?< zI1+#9Uqe{SZ@9b^$X0ynAu4~crST5@U0;|RXd%i+73O}~#UntMO#zQSTILPG+Hq}W zeB?3FoeWNRRALS+Vm~BW=;T1eSMMg^u965)krNqR_DT4rUtZta;v>6c1S)r*)F1t} z>LX(GigS7+c)GKwc~I!vffNH{Vs(+lniZ{CGkXMZWUXsbFVoA2abH23klH6C47rl@G8(qr?cuS5Gqw&|MFb zFKt_DzVI!{hu)J~?=F|&?LKpePfo@TJ{CDok-Mla54qe3mTe}?qhD<#linc3L|Wmt z4{m&X?d&#?+nC9ts_^!}hE)MD*qhl?uL9w7IP@~)*)!OM3xO;zCgdKDrN@NOpqmd> z_5Cp$CrtNJJzKBvjsl2j`6wlFYQ$iPG90h=i~%#YcqJoYv#ADY(O_TRvuZMZcf)eZ zI|wnI{RzVS45beCh%e!L??QOS=}}_9MWt?3D;XfhsXi>P!fYC zlmK9mlSA1gu|_SJ!xAfrmR4qv6+TCbW4tWG>RG!fmo%TzWPSo9IEW;BA?kWn9Dh(+ zUm>0b5&F<*spG_Va_7_-=1tPM8~x>(t?ehv=J~sLBrf`k!W<+Y^KZQ@9~rbHVs({S zV%CqI=l&4|7@kM(*C26CwCuH9X=yD^%bpV7#GE>gu|+7; zCshuqJVc?MPT1~Q-TSw+9IlUPaCLMle%Yl%gI-o!WU;?ZsY&WEeoejwV$kH^h!=c({l^S+gvX~ z8JQ_Dz;+D_mUri$+5Gm#F}0JSUem$j+qs!-Wdl#*_Xwup5NwadMx>Z+*So6*#wfWz zyQ%IkJ3{CRLoa9Uv9dV7KYiR=yluepyy{wj=(3aB-?@_FT7mQ2I@ClVkH0gM{)U7p z9Qar6dib-D!y6IXu9QS#-X_J1&dK3*%gHTFO3aTw=JtxKe4=wEY(q`lEi+vD@_ueA z-EU#G_KHi5HKOzGsnw-NoS!EdT{Al|3n4X=benEI-1&!^%08#Pu}*y74+nJ722c(hqQ5keM(-J`>w zbGJk7Cv35O`od#AwJT@tLbt)LA^tQ{;RSom`%h3!P}w-RfvEKwnYri7<{0h@uUS4K z#7_)*v$LpeI2|7MKbG_)QI;KPstYOiBGvAtUE;8KhzeY$s?Zz;=nqVOKk|f~BnA`d z9+gLLOEm5+7X2R!K;iea^t^ZX)t5nw;lmX*mUtS?+w906b2a5ZEgu8j<)R0d1T1Kc z8ytand)vEDUfOWfWRA!J3_(j@xqWrJ|1eUw=JJ3h?&h-(MzQmHI4(`E1I&%xm2k4x=X)06&jZ*@4wyZ7(&4=2t5ea%61@He9vx^p`;)$@sGsQ=NNZdX>r$+zb=J4@@9Pd{0V=-7i8g#iEVrPb>?EV7B0!WZk*==MV*tT})xafIe@ceP?JSDb zpqjUP)-yxEsYIs;worrON1N=9m_k){dJ zrnWeFkDY(1%o#FMxFJI3TSK1Il^6fPL1O^#qYz^^YGeFv2o5&NrOfYUVhGFjd6~fv z_GW|@0bWdCnMVYdM%^CFi!z@S3Tg?+wYH~Pf93EyqGG2ZoB#9Gpcj3&I1}Mxh?*>T zypo&D!N3iuBE-|t{~O6!dF*X1=g#9u8geRc7xpB2$m+kO6HjzyAqaMT%^UDIPDvsa zAtb^dDuw@nP6x6wqD+oowzScE4yqV^s+pbBhg@S1tjwrzjdHa?ljiTH`y6R?VWHf= zPeV?!C~ljDISeP1waBGB{Hfbc9#X@6g}9$r!+0VLvflT7eEd=ueyBZk875J}7rGL7i{+`$P6 z-N!sEQ{d>GnZ6;Kma25+&GLCclqMtROvUZPnV?cEuyAW7tI*E5r<@+_u@QFjd+Uwe z4AFzVml^AyV)*I&gyo_&szRoY>3n}XH3&}syen^`yirN$$qnOTa&V5;r-cxVpaB|ZHuuFU7&_H1wKNyL%#LGE{tuQ!-)fpPtziZr}a@yklVkN-eE z^fN#0_8iDL>I4&`%oFRIvQK-yzFzXEX8tG@p;r7dcZF$qUI>3d&C4us1s~?Sp-uW;?W6a(e-LS_ee^~Zx7P@sj<%eUbM#mYmqzipI0wB?^vgVxYBazs^9Ur z_ZBYy!I(PgqarIwk0(6%7v-<-xfFd=>)zuA1?$a2w+6xmSI8>LL;faL^50Ad{P!h_ z{4F9Kb+c>i=$kL%lmESa$5K_TR^Hmv@eAgv(-VnZ&+G3&kM|A#fUt4s6!*cK?V6PvcvPd06_3OqD=lfaU zLvOS(rFWs``))Zif~}W&hOuQ!3m@5RzSa*5YbJxs{za-wuD~khb|GAZO-IWSvc%!H zO7o&A`U;O{xGYqatZ;wTe`Qkm1$tmN;I;bo0KE*8kN@?d!&8bMB{eX zqGV6N)FvWGFj^+Yz|KV@Y}>9RaXxst=UszN+)v9Re=AL0QeKrx&c`fxs) zgh|8Vs&;QvvBSB)5mru(>u1I$3g3qEn5!X|#u-3OYEWdN-7U}$C-+(|hA)7tF8~H+ z$$O8EEYg(SmtK7UT$x4#Z-Ko*P;Zhlj?#{Mum=aG#t!j`3=FdVTHzO5nN}#PE9Ri)(AmOCt@65rmaDjU&&GOcmg{zF5pHF(BEuCx=z_MJ2n)D@orH-r2xD50mev zCaNcX=8i=fu=I^5Cd}CHMP;VZH>V0n+A5CiJ}vahaqp7%Y8evzP^2GM_qH)P_%PCe zta3O^xI%;+2M(@U&s)C3CQ+V2j?0IK*blG5|GZ@A(a)1gOy$wB7JrPOo^@%9rn@Yu z1hu!g3xnWGFu9wAOeJzyT4L_U{@-3vZZfC-&n72s-7NX7-@nl7q?8%VJ@sa_o&64| z?d%#x(3KU>8?x$0$8rB4KF9ZMcudGglu@WDz%9rxJ1D}wsu4dimKMGAr8z`gt8mEe zQAo?Rs=LAUCj8e=dh4ugmRq{&kfme~l7@+&te+cBW>oywpy?k4lwS1EGVm`gAM6_i zkTFH6yKrA zhqA0U^oDqyfbYf|$ZN&Y{O1^gOOke+agM(kZ4H-F6z>4yxH(C5h>bPD(cdp=I5~r} z9TYzHyZ!X)TBrY!Na%+ny_j%1-y93DOZA9OeCr_&2b%Ei6P_#ZxRVl_gjoRa4Vb?gOyGN4fy z-poVdip%jD4uvmEUcJ7d-$<;A`Hy+zMs}GTvo!JZaf5z;uxH_mX|^Dn-*Tp2((JIZ ztO#~uFT>~F5I=jR3?PozhhSq>zRJ5Iw{&ATtyw8Yo-O^|X}Z<%p<6N2Yt%bIc|a+i z>y;uY9uxoVmM*t0Fwzz>g;uAihzoTymQW9uQzde7_eT=OVF1d|HL({NQRE+3we4h? zK&5-Md@^uz0P(7>EmcO5JgG;1`I=34mZ`I!Ce@>=sf`-=5jx0dCjT`bzw6~GoFDZ4clwSs zS{kHC`CqkPoG>}w^@&AY`{@`Os`RJyrR&8XM!$LOpv$ej9r0fiJSBj}Q)c=0|8R(l zQ~$QR?zee>Te1n_;VO#54M2A9raxEJ6d{LOysiIgy@TOIn1R&`T2E7JSDU5%bfL~DKg9Z+#@gTe;?g(A-$#v(68m)zM-9!V3E zT&;p$56EeY&a4Ji*{*eNeix%Xn=M56J?JBAt#H#kruXNBHDm-oBn9#KcZoM24J2oS zxfE+8-~@$wh--ZC`MZodgPp2x&>N~3qBj=@zbyLa&7aK_cm0K~FJ5;jnGC??L88Y` zu2fasmLus3#My02ehYyB`)=h5)~atgX_m?Z?b*8sAqUhsQA`+}#p|CVhwc_eSi4Uw>b^Z`B(CkoblR z;MMb`H~}5NqJ3f#97aIm7jA~a*f3IW+0IAVL;#~+gN8U@X2(DV2>wDYWsJ#v@Be2V`YtLQVm(ZM)3~Cbe z2cPYWPk)v(co!R37B)@||Ldmam5g zxSehQt~e*fd43rsw5~`My#rKTlAhuLUW@Fd7D zGLgNY(}XEqoPjsHTs9caj14h-Nchq<8L{U*{yr~B%P)zgJEcIh<#NWX>!Ski`BIjT zI?6D#ZU3p)wXb(a0mMilPxW_3fzBtb>4oC5;O!MGY^y+vy8nr#v^$>>Ks+OUd#(A; zV}^t;5Q2tPRkbS83VZjaFz}s27--S^3TqUONq-6QJr2-?t9g=Uew;yJ+dXRBvOW)j1E+w| zAba@xvTz|BCS=3{K(zb|MTM+I+z$f$yUo+mLrPYeOuuRTzYNmJ~NK?+#@f!4MJo*7E;Fl!_ zq81%=c~M~sZy@0wBMHVVkJcT`;2Go_=H}VxZtB5)__EPlykR00cZWm&3yT&OfWAC& zJ=c>PF^gtYyTd*h{Q%XvXoRS~avd&%%oCf+_y*GIH=laN-->DnvVbe z%)g&bV1vp8ZJx`a8F$xOH~|YkI6l!KA)KeZ(%x^umy;8wj&w+10XEavgJSM;WeeI9 zm*Q7HCR-Hu@ylOSt}@~?>8PwthoYu~POowgXvbV1&OOv1{f(gZFXegcVGw`1Cr;i2 zRR<<%ECB2FuNUeOw6kX)hxg;jgOF%Ya8m&gaw;TZo(~JG)xzOlm>Fv;{6K$hlQwg8 zD?PKBe!KW6vaR8pNcnV}d$v8BYhU3Y(rMIvskA((XM6K-)ECnv;&$cB&#d3PaGiTWHsxkLSaR@qjUfTQ3faUr1l|gMUQJ+4bovJPj{GC~K zo^3J!a66(%Nb$^W`9|(s3qDo%0|FYh{>YlSiWwP^{ouYQ0QJ!WztTRY_(2=<9-yKE z3@_iAaZ@dv*(=klvRFK_em_q*Zxi_@wsyaR?`ZeJz%0#)TAx%8j5A*43~l%GFAyc= zqsCE68+87}3NIA4li?nThlZ5ijs6Gm^1LSmfCqrq5i5U>z~>gV?Y2T-a=Q1C;{f8n zmT8Imd{uD2KIf0}>oe;E)df*Z;EmPkh4<&!3B)|(F(pPJ!okyinCD4w$HGx81f~(B zttNU~!aZIl!JV{4L9tH^7Gvh#u$8s4F}%0My<0tzCM!}?lRCUja&9&|>*`;$Fay|a z*2pq+cCU`k7Z5SkXlRg~QG>U2{!upCVBb4YU@yU4&QFXcpNElO%DLqS_t^Kk?E9?a z$;oEicK?NaUNG|VXDb+(@Un5A_wD?&R?oD*&97F%;Wwo><*q;@F`Mb>WVY;4oeXgm zE}^yqRM^EXAKO$*BR~pwVN=iu*6CHd3DKA*NZMOwPAa zVamV7yyin?mPY4r=Ns(&XqW|VPZzOq-mt2T&XG2=&feU5OG3XS-NP}&}5^$gGNN%quCSC<>lNR_L#MD=IgtHY`dE)i4)Dm z(sdiZ2T1mN-sCK+EFKmK1g@vO3*4V-_)PnGYIQeNOG0b9^KX?8+mjLp>{kWs?$k{g zNVb)$$On-&@{;SCjWBu_$V=TTj;#tETm)Gz5hjp}P z`}VK?N)(G1&R)^3>H}u4j^|HCeXu7UKhdA1GzKSnUicQ*^6F}lL^(5{TFu9devUqO z*Z?h!io00x0ENNZgWjmy#L_w~!Z7FFFWTs0EDC|I5aHDa$puj)q^7CQRc}8D+|77? zpYQFZU%&OgVXeo}yd!#2jo~X(fVrLTqVa$w9VUg#u?h=+3#*0=zkBfCAEurg56-Z# z^NASigMKCUh{nU$$JQ7z`XtL_zJeX`t6i^^lKCU4(oASoNW8?d(a+7?s_>@>0tg}`R9A%f0tH{w!H)R2e$IXq8Pqw}RKpu)2WRm(k4f>~_G2q04DHrB*;@a{F zP<+{Nf(w9*Egw1T*fA~9V-lwl7n-kt_=gzsb5i`%kF$+Bg$tyi!mt``NCDyzKrY*| zF^JQ@@od^LD)vD~Fq(&xo;|x`N}V;vUoqy0}kna^EM;=D6v;6 zJE+LZmJOTY*A{J-{=ks*9*L32%R3|Sr6GP(Qyb@mz!v9g>T{>t=tu1}u6`#oZao8T zrOVq}yER5Ua*kKzS8l%cy-n0TC&%sApI0y3j>%Tb=cVbBAipMBLb3P>@&mukIGy}^ zfJ$-z#z9e1Oh6xWItn}@=8KSjxcve0Zs<8rW(8-+wY|-~>~Ar356+agtp{P(->1t% z-hXC|?bV_tdU1~p4&X@uULiGAe-dfAM;^Ego7be_({EDij1iBzq_R_i!c^eSBw7h zH2$^>DH_QOLAx)?B!~cJvDK~L1#Rdt$e`b1XPv(qe$$_sL>`0vu&~CtG)jCEFbN(p zZ954q2`LlB81WX6?4I}s?h;a~Rv=d~+tRJh=-d?~cU4>cUXjb0KFCQDRLKP0IAsCS zLQ4Qk!}1U|NFZ6NSVS-hOV)ptdmt)kCOGvls1YD-2!0~~@UP_Oi-014KfaRtFP15S zai?d3OMO#9yq|;xls%Oj38G7pstCrTn4@x2++fwY3yR)~?fgnMqds1Eaq)sU3WK!kr|23VZQ~OundOyj20-% zw%gkf`;7p^EBDDHM$rq2iyDxSv|d?Jg{FkF^Kl8tOS)|+Vjj7)?yGa2Ulez}_|PCx z{cnnbLf%88Q0w5}@ZV4W14doDZ!&OSme48A?2s3MM-m_SQHQ-Ub2AQw@#tB79g81L z_#O!rpag24^Zhig=kl6mi8b>(JjIX3YxT)L}hHVF5`k7Vc+jT)@ z)@OR6;FtAO8evYXK71NE{K>zJcQkx7j`Xoy_=+D7Pk_L0d9yWhdR{-&~ zRb`DffoaK(3RlGZBXM%7iN4mqJOWlQwM~wDG)a$dR&C{=Gi7W`C0Dvxq-vOq^`ZXl@$A-;M%=wABkApz)A7|fQJFkKVMGN;?F276roX zf&dMFk^u6G(opPf5esnJ1FK_{$=ILSzER?4xC(@bEmGjV2&KSWPy4cY{VeXlOikXO z<3{sKEORM~Mfh!JK z``NUlFn7rL!s#tc7-ZrJ2x)QrzMu|0V5S~?O=+#6p>b``X7cRl((RDUlO9!f&S8}v zX{}-X!fSVsTVW$ytk`{i8($llk2}=21@IZ4_v!rRcnbS&efmVCUGAgV zS3znkH(mEXBJF_{9P9lGyv^&MgN~B4aK956Kc$eJJ+-t8=TRZf`U833ZUms#?j`+^ zBC>~m)8$4sig!UzHS+Y-d%Ea&!_6aGvG_OQ8 zX@iW-g%N23P1RYF#yA{0S@Tx9n@kxITBGeptqYn`f(mO;qNw@e;eIOB1!QA%ZqF$( zxK$GY)L&(7A|%q!xpW~fq>n5B>+*)TY=38o>b*88T2i3ZqiT5r7p2E1y#T=co$eW5 zn@%n|I`N|Dm#Tfr;q7USA%10nYw+t|khYnH!{ME-iIz_iu~vK%>2nrxBYj@y@TM}3 zY`dZrT8@ir_Rb*1Kst&|l}DDE*JI@V1tij6SJxxA)pzJO-@o@YOu6onuSx7JurDcn z&n^k^pLyz@z0lqi&La;SJ6#0qqmbuq^&As5ds|XwYSJzy?G9dC-3&EVFx2X9Q!yxE zvlXBR>U0hz>&gL}2io!p0p(mQ)!|4shV$6oQ4r1Y3d!FB^1n#{5XH(C$ab00+H@(p z98qP|y081j&1jfT&5Yl;wk9v@G(C-u0&8g^E~Ek3OBSH&aXz(tF6b;t{wdzB+$L@| zB~5DIl>!f6+U@?%nguF&*E(wjCH&LxI>Xr55LcJLU6QzF@(i!o+vE%q=-SeEJAF%K zS8#h1V%pWPlo4<4hDef~Ust<~8?$Ot2{tRx)mn#1h5;KJYPA;}*u2;IrR>q*#h7@y z{T_994~al0v0&*1({Q`$C6V2sw0Xcas#)Qo0 zF>pU!ioYzt+E{f;HIdP~0stKVPpCZ;e0TnMK`%w%Accxw|69nnAX^58IFKILVd(!@ zfUsRXJG=BGdX!bP#f?hb+J0eMc~ZlL2DgYk_g=4b%Stu(I`<&Y`POYr-x2${ez}`Z zzf^rZDScESP-Nv39eVm?&U1-bB6wv?bc%eFPN z5Z0E0^KLG0Ip-i+9wD{;kFbh|zKyM)6JIlj=!T8|#kM_`5VIUow z9ua%1^*ivMmk^ABCjk$Y)@U8=1G3lJUN6>eGbZ#w)!_vst9tCEJD++?Wi6*B`$mB^ zIm8QwLCoM=U{U!%u7gAk$2UmyyN7HGiO-9u@XJE;wwzXVo%xp868B_5F#falBUD6F zRPZ{ctF9?4f?=#LIzUhxJ(U+vGilL>xKXWN__g&QtvDqga<$~@^Vae$P85^Uyr94T zrRrge==!P_>5L4GK3a~1~q4u>oTc=$Q&!l{p zXNI?NP2}E(WvZ16!2Mt&`YGi`DR_ku2z+VDh6Zfazb z5Ag1wdLKX2iJLJXHWHQxwPf(-0{r~Rf-JGQ(#bgr`KwpwbDCA;fM(bNewp6?n|%B4 zMU-i+M+U?L@5dQP5+Z;)8c-h}z)rLs#_p92X!6IDPQ56*{P5A+5@Zhn2FSOR0(_cyuxn)BdWJ2?zx38yay zVZnHKn|Oa%0JRk{ixqm{&Ltgof*=^_%xo$!zitm&)bVfJR1i2A#8mC-^pik*-kAg; z$m{@U)W)#jByT2-C1`;1$K=@_`_!nQc1>k8dUNjCIOh^@VPpCVB9?P!cl*UZ7Q|yI zo^ODvD~Frzmi57l|6N&&XkQJ4s3j!>HS4Al5Z}OcEMwNo=}}Ss#FeYYlDG;qlx+&n zvMSU@5gtYW1mIf$-<8|Isu1<;lXQjUz63AQn0`RVecLq z6EK4c^qV`m2w7MtjDhQ#aZ{f=Jmlt5@e^!rtY4^6@Fv@i@cWMffrYSRV`DGadR**N z$rmL4p>3=F0jE0LKlaPZ1Ay%VpT=F8eku9%z$Fl(X+j_qJ{{inRrDbAg*7GLRz@M( zr0}Z!FzA0rQb7C6S;z!#OZt#33h6|L=BQNbpP({eJboXV=RO?%lM#k>N9o&&A)&(zELS zTxpv+6gjTBTzz7V5D{}Tbkr$}w%C&@4w>&@;H_xTWxuJ*IS@b9oHe%ed9bOod!gI($H)RVSI3!v_wT_f*{{s2dIY56)S{TN ztu=E@@WA|$w`f zVyC@2xKU0=9K*|tsFZ*t$V-s#4-JXUZsT%&PE%apIgQ`Fo3h&*gid9Rx zX6ehtNZ0MD8ZAUtedRZQ7ZZ!h;j&Y#*QUQl`{y8O|F&};p_JIYTe{_?3EeM6%O_x1 zp!YU-_Yw&_?=Q~0`=t1-zuh=Teyc8pKCm<=smJZvW)hmrq}r|%3)@_qll!M!szD@)9BuS(N070S$Vgrl4(=Ez)GmgWS^uUVQ|&dLSz8?9w7V0cf-MfTes~6VB+T^LOOpRgVfd>s{9(o9JKaSn+S1sbS#-Hb~SZg z@dbRANPm+jP>Wl-1_l8`P4X8G3mCzW$UIK!1Bh{WyB>~)^eRms>8%k0vk#0ff>}Ck zD5^_-OwcTR%;QnEwvwX%(rVRl)SdBXZHJ0wcH~eS=VgKuuBLHnI_mL7e-I0)F^S5(Ss#SMvCn;ov5tIO8nQ6>+)zBDK8c45iitES9 z>w6N1W0iiAQlCC8ea0fil)T#;=!FMogXfe#Hn)bTmG9js|Ncps0zDxF`8TlISHAE< zp<9yELAihqN3qTWKwo%0#nmrM4UP?Ypf=w%224$>L6EC^9*{S`KCHjgd(8)0f7!E_ zoLv#5NJuP^n!GiluVaq=4BWGKwdL9r^xSd5We=l+%E#`i#tDY8h9|_d`ap}Si-&u& zYrF}qrb&nHBB?ju?oTlXzh64l36ujpsK*A|N7(J!cF3XboYHrBF{f2;$cYNB;se`P z*E(2aWW3yh@z3>%`2*4vN{sh6m8bSDeUKXmJ$+#v5%=SsdA~fFlw@?y|6||QZkFD< zh&AJfAi%1ldM)oadA{f*#dVVMEr~sf&^v{YKg%xF5)4`T=DS~g)ZzC}?%qGaiPK-u z8bF5Ml|G~qy*DSS_<8Y{>~zDu;~0MtrH$?iVe&%mnOZoQ(RYw)+?$<0^F206ICty1 z;JAdy7NzY_ay2b2g-#S23{T15`6||q!DLrwi@ut$WQonid#^`5RJrg6r<(bT_uze0 zw9y1tBl@4;$N{mUu8kw z+)d^~NrDmgKckK&Nk+%EdS$+QCzQ$W33 z6Ea}Qe0CNVwoUW-=;AH(%R*5zND_p9^V;(g4{Hvz_rBZb(jYkcp*Y(5hAsGDSip4M z9e4gt)3I-7zZpjOmW%#S6&A6SX%pjOm>o5KL#a5(n>zD2X)Hh}KAReOIJj0=J_-llgN_vP-qi&$h6)VMc7mHAf` zcHp$X`6++Vh@h^LYo{wWI+iK;H(H?n%n?T&dmvflfB9|sM^!=X+^cI``2ly>_hmx+WYxB*xZ#byuX-{e#tcHr z0M|1s?oZs$NiA25nHD0iZy_Q>2UolOG#o%R_S{uwu&5Ek*DI|O*HfEGCVZ-g>Lo$y zwB>F4kD9l7`54z7iAiIqpQDytOd=1X=Qun(-?SEkpRX~ZJ(;^gEAk^{TFl)j2Y-3&+SJh<#M0JkGqPryUTtyRn5}3+pB0#(6 z;TO}P#GV&Or*%GB+a;9ieeFSZM~-6x>c6H4=P4~MJq<_`H}{!No4{|eTErVE(nBxo zQ$wO7KTxAuE3@T^`~IiMLkvAGMsoKV!l%U^k+@r0}9kEJ{T{8$trd>dS2Zlr9?7| zL28fx$CVNFG4DTR&?f)2&s5$Y@vtXhrKXpd-0Nuk<{2JZB>~aJeEdNx2*e&4@!J2E z)u9=5wAiue94o7h6f^SaTKwIp{7?T~o^P-}?uB{KR;fMpUd=19nQZC`XbvH7OK*9n zDYVscO&YZV>thw0p$C>~|Fp0U6C(xO2FE5?J3CW^HFndUL<@Hy)=|yUScq2Zs|pLs z%;8);FO3O)zq}Ym`R~I%VaT7gv5yHeBguwr#Q6?~qw}kBm=X zEn$#8+MZ#11Vwtu{K)hDbGEN8Ie8UqwqH6Tx7VPvXCNfKPZfK7==*#=$eoH0+(Kuk zn}!VwQ&xH)&K?Y{}`g6UbX13fleo z=2D|vC~`MnO_)3zZ8FF<&Hx~=#rWt+>Pa%lHNf@A^DPQaT6uUW>g-jx*SVe%q3?q( z%0?d_K5D3(BsgK_e}}UeK6)Fxv>bEYcco-?IIz~KM?aCw2di=&HAf`t!MX&cX3O5Z zNg)#M`~#9#Xv@YORp?T~^WH-mdbqN=-Y(asC*M{BI`pFkK1yQwe{^1Qx{anU-Mf>P zBgo6$zqsIQ$_UrPFH(tGMCv1!4-vl-?^!9M6&E==jt}K#rH+8@Uyv>A4lZ#urD#98 zB!ITxab#AIc!=OgTIBJ;2AF-r3QN(V`nbk6SNXB~yFTY7ZpR^*(um3~8t zi~NN-KNK8}6n?-+4!Ksp&gTzi)pSwl|lW<#k!K9RZzn@eh$*8z&DAXpFZz?*~wX`g6rPCD*AM8tPQ%B(VdvNFtiaRsC{ym$Tj&fj8m%}Pit{1&d zchRX-o`Q%j*FElg&ZX6*6BMb(Awzai>RKAlG#*G_^p#navxUK34u5Z-un1@Yg31lT=L|6i1$B!`8y~o8u&}Z&RF|02SX6|dD!i~6Ttt+e}fgEhT za4=k$)u5+LfRmKJFgtQZifi&KwL=9clEj~Feg}FMBi52Fe!vcZPfO(&>2N|P*dZPxGetEl1n8u{`U2lj=^9v?7~yd|V|OF_=^h!x&J<@M#VN$Q_kuHVk@+{@ZV`Bs^O z1O}NFL7CO-yNb|^ZpJk9J~k;lxj}p&{2-^c%gM>r*a%}5XSfX$B=Q0gcGyCuT3*o9Fy(5Xzp z&686;ru#q`4P(5^OP9~5+cVu0paG(gY`|9~9oh+8=kUsN5$``A_|L6Q&@Fxlg=kjL z6#I|%KIaUPYum?-96iAnD|Agg6Xn`uz-NDSIDf+X$viv51I@=r%8&j_+iFGJ)0KN~6A+`TZCRb-}~f&~Q-Sz$QxS46RR23zk-x ze0|}EAB@}#%;oVv&*fK!blDt%iIsCp1==}2-hDnyMoSn&E@*|zIryK*_{E$*l1}~2NfoJY| z%p;zU=5+3dV5EB!iUQPTKu*qTi{)Clqn!XBU-L~@(1c#93Rf6cBr`m$30P4`1;{+l z_YAL@3%r%h5*nlZY;s@%P?gm+%-KbDUgM4aXjJ-+)=1rc9HhR$eP_#5z(I^roMm$s z*(un(u70`^SIRDV0p90rv@;7&hTx1fqLSDIH}Cz(Gi}{c#goSXmWJ~NBk=st<*e46{+}p}>$`IMQ zG;04;2F_bJts^0+Nf+cU24rntkID|2lxdejXHnlFHYFaV79a^n1)O{S{u#%sBRy3h zeOG6H1e717l-h7h!VdF^1>uV%@?NEZr_njto_93^f`Q0Qa66NnhCVOrM*H?S)DRq1 zppLRWT=gAd&UEj>gg~#Z()k!Ytf&C3BT?(yT-*_j`fEhDz`CTXC~kVTX~m(K?~^4H z2Tj1FONexo@V2VCIHe+u3M*_?5~KSO3@T=PhHe`YZ@9v=%J|Bd ztpWVQJPWc!&fO%_`iF*!T>^5Ill;M-41uG^w@okx0px#x!F_Vi6Z7o*^}+M{+-drw zrMK6sc6aHwfVxM0@^$Cx_)wdZ=Tyxhlj>!0O83VGGDK=Ecg&-a`B_zq2@{3Wo2MM~O`;kACLai0&iu|Y>jrRl{>(5gG zwOVb}~;e3Z)|Li}-fq-rQvlQcRY)*E`-gDY^epmxDbJ2)^{+*qQ1h=SD&7(YY zR{_`&w-*;5d)+yM4lm*EMF;|6Du?@TU8(@joEiR3{yLShocXC5O_oX&v;_j`1sKBn zkO|Y1f*3k1%4l85^`3oUA3eO`r6I7Hisy_M?RYL3Bv)(Apzmorr^T!BFn^UI)cZ7? zF5H7+KW3)_O3ttlI~5NEYsH?$mb(kq!8u}@ZKa==CDM;>RZlt-bieyt$7%!u*+3KE zKr!kdGDSQxy+Tt!(*LX0qy^TtyQ-Ivc5$ny4X z`8P|w!|Z>?yaxzXk`Y{gLkqZ0X_^QCOI~|^!fShzFAu^XO(4fUP_l|D4t=ZSTd5s) zLrH7$$tODQiK<2bMJea-HG#vC0l3nv?Sh@13m}7R08?O}Niw9^=7*uiiT+5qw?A%9KXZDmzLQHSP7%;xg%Xq@}K5#W3p*N5Thx3BHS>H zgEq_w{ICZ9eah8GSCow|oq}T>E@T)6SXc@bSPFvXmzn3#7Gn@VZYYlhj^6bi~7~>!gH;8&++RxQMFX*-%HNXWXY@yFzC#;R# zQX=gc5cZ9H%r2RF8JCntiUI7R5Pu^M{IqI{-{Yf3M_U`tLuz7Xt1_2Lwn2irTS@ar*bT?);tvlV@h!&pGJW@xK1< ztvD~z8T$lA?1>6}Jt&FJ)-V?@s2K~YMvd2Y_Bja~v?m+fI|;K#Z19ig6iFoI`^MY_ z)zJDRqYwXT71{|tK@gEin!lSQ5rp^nr3kpl(Qh|D!pC;;I34FlxYYfRcrS$z{ zeJfJcqZC_9HSqlRxYOT#-pJzIGZYMcB><+|HrNrfzL*qsCn7=t z=h9N`hZ0G*dc^d*j-s@rnOee&#I?1M;-oA6|6dC*N04%qAL@^Qqc?Lc`22MQn)(Qi z0Wxn?(A21#dUj4Dvi*VgiH-HPeF$yK)40=h@D zhZlIs3e+@CSM9qY+i3!|Dby1%KSjrU3Z~?geT8lUuqfAT08xAC&nmp zopF?r0e;KKbK;``=uCmoxSE%S|GVh9jM~_ld&2@FOW#UUjd#}g% z#?j|dACB_V+Vc6p3#aNgRQ!Cgx7W`)FIeR`HHJ2tN7XpJtw~S&B3BuCVq`L-8*^TF%B{j$+P(Xz#oVI)E89Op}LY@iBGa0HE<; z_w3(I%KG{jjhvTZK-8`V@#60%E2>%jiDY-r z%?n)PLd}&k;MddH>&&cw>;Uhr;|8wcR*rTpsa<8VGfe2v=s>GX*%dDv&b70Q)5 z$Fe^%>O`uluTFCHdLs|xfh8p$Xac9%^6}8CGCC_?m`-0_b3i~iHi4g5b4P-V?S@_8 z=Sx@7B4uh?A<;$`N0w!Ez7&L-EKB59>Gzy`5GTlpY9w9p+1eL>Zl4Ws>^7aniTaMD zGl^`>Jw8f35E;#C-+nyM4e5H`#qD1qM4bE8l=c8L@6-0LTN&O!L@yu!^SClr!dk!r z72KO7b<;lmrV7|+&Cv{YR4Z8agGz(~jQXFqn>MEp?@QXUQ3IJ5`+eV^6ImMlDDoe3 z;+>`I+lno%m$50_=QM!0CXkh;0r#m5;=0lcFiWG<@YV`c$FAhjya~^CYKKs&N{X}; zhIHBZCq(Rbr?KIZ_hXTP?w2RTjMI;S8kHlBAXLA8MOO~LZndzob9|?t%`R|d{)YG1 zE$++s9_|i%50ej(^tkay3FUq? zAXPwaYiDLC>88_d*fELM=cLf;gm-fK3Z?MCe$ytI92@XqAqBZ^o2lnb>XWe}B~hSm z`o4r-GhMJH6 z=e6UU_N8j^PuR8NAAZ5jThtkK7R&*??cuL7;cM~VuS24tO+kAe8*xE?0rp=9w6fFc zRFAJNe_7Cb|0bXReaH#8flo!{Xw%sf#QYmX^4J@-q^EqSfxN_GeK9&X3}NbO20NU8 z&=||=wt+cw%m)dqJEPs*BW-5i!@VYqQGuHme*gaE@B|J&I9>Sj!+QHas4!%%t))J0 zFngPn72*&->R#kwo5$U*1`wUS{2T(;elRmtxPJMdaSaaE_paVO1kdGvTb=8vjyoC; zb2bn7VpNRy7>={JCVn6fv3xG#X(r;VWI3*4>CG5#;w#dP!BGv zG$NZLoyOVf3i3W&$vQdoXxq%xSRE5IBp=IvufwhCjMc5H&VCD#Ed<2PC<7DmVKW6_ zq+FiZHg<2akzFlp)vv`)x$U^AY8=SSb{UW-vS%t&1}e@D)U)EJ#b{zvVSnx5SrX=H zXVWAApVGIgNj*Q@;1~S#uQug^k)2>5*;?ppGwG0fU{fHImI1HJUr~rRi;(b-qe61EHQMehQnWR zO5S4RUv7WbrS2}Mcy zTCoSQ<<3GK*JGT;A?SH6ifIdiwTNk3e7A+kcC2pgFll@cQuEu{DsW@yHVchfF27^` zhX ztuSf!78gKC(VSQT@UD6hGIz!n1>d=FBk@%nDN@Fb9TIZ? zU+=r_J++-un{n|~Y1?WvM;~>|Xgx_D3o)HqNCOa4{w+s@*m*YKI@2)j!yYH&(NEYX z+hS1dWODh@$breL1|p|*tK9lNJ_;r#xu4c{6ugfDGgAT7Q?53aQG|XdoI1J|&eP8^ z6{g=78}82mLKWN$z2vyx-n~-Tr+XpuhvvPew`Ss4S6ATATWK7OBbDzqJ9F=+j2w}} znI2Jcj7qk+^8*W+GIeq!WSh(y%_OX-Y+aCT+C(=~=CpH0+IBu|ECyek{b$+vP5V&G zP)UK*zIQ-pOWHo<7;0?558#99pW;nY{jcMHI$fR&2XfEISOf3-Uw-SocEfJ$t|Z8j znJhp_xf{_H;)e1*UeJ|G?E|z^%yqTj{h}&i@i(((^N+&) z0vQH(wqcxa+p*Q-kKsaTP4rMPG|slUVDw6!up2W4V7!~3e_+}DdxZAOz3%Sag>SMf z|DRmF`7YZWH$V@>HgPY=nuU1BCLg}uBILvF(;8}?n~mIWiXP{ptZg|)j!kyt7}pSv zY*(J_VC3Mf#deF5N~1PT4ceSI#`Kj^xa11ZKZk=)^;?T6&h;H6jH%asr`m*p9|x|4 zaYq7J`g7ksh+I+{`RioHhM?PgpXgF$q1g4Rn;)vPU1Dy8h%*_ikNH?=cV2zKLmNxNT+;Q4Q~q7kYM)T%0=B44u*l(-##9 zTTw$;=L1V|_L}TaIfRxL8iu<6!VPvTKi1a@%X#mB#;iAhJo3QKEc|#Fv!F20La&Is zfNfqVe5xX4Iqv*bm?ml>u3(B~&#}63(dM(~_zbPNeYf_(Q61MxSU*IBX_%-24t}1b zfL`5yU1RX5`3de}&WzN6w~}Czk#lI79Vl`j%&~KeX)HjrahO)#0)ieaSashGOWnY3fp)#llA1xBAKDusy^U{#!!lC3^_ zAIBW+zPtN2^ihNMKmFqBub!yya6`^6QEP1v(ejT6uOAZeP^#!|T%O04cigEW!G(c%!MgU#)SZXfJuiC9D zL2ev1ohOv?LJHJu{*+}Vp`GK<;EOLR?r)?PzAR;`o|J3Bd&buM*u*dslrk$A1DNj~ zsoZ~6jlFIay*kU`b4Vtf{uxcm@wGkfwQX9W8HqEh^`xAZ^98_$G z`e*CYz#mP*A*o^V`m!MC*{0dG!QuWZ&o!_g&fOn$NX{w$#2+e{buxxJXX zyJvQKmVZb7`xLdIR1s*f*GjL9@d4}lTGG{kQ`h3r%JDF7=SB@J1p=9fBH?n-6)I`Cu;XV8?DZEQ-v5kE#&3k zMTVNO-3!sA9C_Y-Ra=FVz0$WZIz4EMlm`l{R z&sw~go>iJW#@oqWUHTsfLZ1y>pGM73;AuE0brH2wqs9SH;>3;%XM)6~CM-7lK+51r z8JO!sKpFH&M+?|d29*fE#k>_g11dT2JZUfS>!}uepuK{es9mZ&feD$kt@v3ynUXI_ z;bPS>A{zKgtE)V_D(?!=a1--dNa(|N=cqE*Z4O@PBjDc{7~w}^d1T(duVFTK+zu9| zZ4Vu5@eCv8i&C^C$BNBhl|(o~Z1bUGXEYyjgZ}}~-EZ-ho@g zaU8+s)=}gBTCe#qoEg(FDkKugl2ToKyx0<*@f%Z7?~+Kh0=gfx?ITH40Xs^$i#NX-aAFD^=#R|}@xjzX%|GXome7Ps-n#2PAuu75|(NfP5Lp^H*zGz{KvP&nJWBYhQb)0EBlu8+Oe>bPb`@{66R_c zZWY{aL+}%Iz2gnf)-3t*WpEtqleO6p@V|j_4D~|>1w$T2Qg(38EwftC%|BzVQ3=dt z_LfYIzM&U+KLtK)y1w_`<->>aOq_n*ov&b&KD{Xw2m@U?hep0u`N(~*MIs6I{vc69 zz2iV)X~2M9?t5M|M|*d2RFt12E+bF{ z>-VPgFRe(1#^t@bBJQ(oi)lKw?E8HIw5f=!E_1xe+y5npAU` z(JB@i6sG1lHXZM6s7jQ^7y#%NG(yf2onzCe5w|}x`S|+7H})ny7LaC{jlU2R_m8PY ziC?C3?wsT$-r}SCBmKvbOCmU2JCTMp+EEMZIl>TmLiV~k!tgkPK z+Vf`TuPtki;TZI_-8Kv@)#WXsB6j`8K0_~?pI8=HhA$_)vVQ>6le6+vtX)c&_{uIbs6nMv&}8YoD8H!d z_XAb9&ct5iMS-+1T4vFRM7d=aQI-VUfe4|!);&OFtUO7biy8!~h!@DwwcgDj>_pjW zu-2J@=J-w_Y|v4!dU=ADs_cNZozdr8uI4S&&;wvpZ1!;szb&B7V=!)8A+8-U^T+i5 z6#*KJiDjb{V_rDl@BCljQIlft1NxtH9VO0y3FoEfQI z3FytAAE^ge6|5ZlW16GW#{2%kpFO3G7|#QEXxg6#i$A)lY~0|X=lc3x*#JLi?F6F! z5-{Q2)qaf75}q1?p{$^1QF3Ag#JcQFvpZL^3DW{S>c3r9-%k@Fjkg+^`_vZ zqf5ozUDvxR$6ucZG2tyVVj%N|7JmZLi^Cs_9U8eV1OM$L6B`Xf+*eV}O9bPg+;DotsV1%-M_D{1jY7+G(f@U2KFjSn{v_gDjN}51m0M6bm~0rOQNL428@T* zB05z2WPe|Ge&nUH2xCAK_^fWTOQ-Og$Lz&*O*Z^PTZau5!%2M38^2bTCiM^K(4 z5ekIGG({wuf|b9PAHUF*V)CyRVcU7?9!s+<*_Q@4IT4yZ1SFCrzx0m9e}EJz8ZgE z0WNgdFY%-CCvo zPDfy`4)y^?JC8HCmTcR8BXLbE!Iia@s+9cSV}&T@yap%w8T6qlpah>$(u6tKZo}Q5 z;j+x3C2rj|-ixG)Z4X7`-&%p2-|M%8) z8)AR+;dg4tg2!L!fR;|@ax=PTd;YsH89h0AMU(@$T@3}Sto$eMZV!cAE%}Qv4>j4iDB(Er3fS+E?ubq_{L-=Ss08)tz1>8AJ z6oBUdm^P~Uas8LVman=NA7-vMCeSNlneheR`r&Xkgy#yvE-46ILz`IN0USM z;r>;AR$$g@$D(jAF)pN;6JOEEh1Iv@x^|VqTUBj8@x6k@lthQ-abh;)ECmisg;$aO z;<%Y#;S+aLnz&X}!1M0TR$wdc@Nlz`ne~S&DhiqO(?dxED8@VQwHzukpzA5KBD-)Z zz#^s9xS20P1q4Q>&9W>6j*T~~)v+DPxF4f*W(>2CBk$xx8_M-8N-Qm+QZoe3R@9Tw4fv)Z_*>@i5tMJE{p!obZp_(v5$qZ}Ziwj%!vW%*!YCI#t9Jtnp44*jZ<@0ghNQde98Y z!*w@|C*A%a_AU~_aUR*+E8lBXa4xKh1x;WsnsjXW=eo)9l@+S*)(vnwyS2$Eg#Yn@{jF zN5?8TP6fo_BF)lOWl8@L{Nc|*<9Dui3ei-|FFhxVDCG42xvx=LT2ogiX#ieTJ8|R; zp2S12;r}r-I_j&IMi!F=B%@oGT&G0@FPp}dpGfjFd**3tCxej=Q$~x;%fBdcy}7A- z*^suSuDWHR%oSeapolfT=_CcU_w;BDfBS0_px;^Qn!{>nj?pdiuAM-we#$yp zsIg^0Up*7Ce-ZiZkWfI#b~LU!lI(||{?3PI)4qrPYHIpF!+0Njb9j-gKWd}8&Iuqz zdJCxmvb0TRNNcoONptnb`Qt6=;)?ocd$ z30Uz+ClHkX+hUCN=g)&Ts0#;)jA!<)kXPebZ{O-TJDziwT*!Kw9s)rdx~Wi7;Lp^smb+kNN8Ww56L+hV##FxJst;pSd!RU!+<&!yK2D4^Y zD<6Verp(iZ8ham`8Hl<9$pwKKD~RCKK2Dd7$7x9?fVKycxX|Yp^fUzgXLalU+|ts5 z0qot~)1`oeUZ%TiqEO=4>%sAD2(C?nRyRjD z83wwSmvN^Ym1&<`;!-S|fN;!t<)tr;K}_u1f+N zVgPi9gZfQ%`hm{b#4`VeCK)iS9F9|17_ECcbRPgI!+?Q{p6%(4&YGk^?qR;A;y?}SW}^H;>NN{ z^ZEZ;fRBA#A6_|#%A$A6vdAr8Y@U~xs=$uiyDILscghFp8`OQWgD$qFspw{CLJ<0E z_?)iG$=B#TFK{!;5R3a1GBp$-Sz~je*Wu;bR;o4s^9D{x5eo~BbYy@d>sL*tcfzzh zPKJebVl7VIHV9LFJT>+v>ex#=-ZGa5$OpYwCwJ$+XQ}}iJ>J!MPw2#~CwxQDMpoDm z9`fHZ;0|)7PD~vy8ezosm&gN9Gs3%#7ey-=Rw4}I2Wch5Am8)JjX$sSzj*816fWy-u#+%TjWu!WYKt zPfJl|1CfuSwST0&-vJYP9utPNUfD-y>DMz%3b)X>CY%ykf}rR{7)s$A4o?0s+H~+h z6JTwHwdeiBud~7vTAvDJ=e?09Vyt^gpGX!+{o>nwVVdeA28-=>XYBh)!j?;s9dCkh zK}Q3g@lkdN$GbMr$7>7K0coiv^DkO`raN;3O25r(l!*{9L$%S$hCIQT3&U9f2(vHw zt{1R)!UPwd*8G$h77SgnUZV_83{=Y&i%ZhVlThC#cg*pJL;qoXX?#3i_6Ie^p4|r3 z85rejG@3sRd%g;NJlh>YD*VVxQ0pKi725GKhMkiKz!Z;>z$=_61tMRZX_1^3x{ZSo zkF!!ciq(tuC8f#=kJ*A6a7m!Emf~nki$ne$Uu^K&Geg&fT2;(v{<1ym&?jjV64uFc zAfnMoSYRiQH)&D|C^#$mnzN)sN0}V-VAKpcjAuP}vVw2CP+AJ^1g*Y);@a%Stg4m*h15zP(DzMJxfBhD zGH(Yr6165a-bFSNX$mgS<~ipShE{b?o^6ZD?VkPZG0855Ly9F7il=Nj{QE9-CwA-m zfX_!W!p4^L+KYHUi6elaECAy4;?;%fM@ed30-Rx5GP-I`!(r;x!QK*iIk%gyu~dFq zQwBR|em~lh@3?$5#X1HlWI-J~-e`R=CixQ_wp8vLz z222fYb;wKe_bsIH%$r0_buXMtSEgdk&o&Q0Fi>JCCuVQiw7E0eM(Y5T2tS^Yk-x!_ z#$a2j!ospMB1gRsZ~gF^0ns?CT#0YAz1P;J*n@Kgoo~-*A^tC<_ix~~8g+8(3xo+l zs`FpYq+W+XY*Rr4<$AzkT-yd9v%&oV$@(wKXicx$}< zX4pWh8L-1RZKpMah{D?NMrP{+j@Z>bM3Di3EHVEsR^cKN*?&VMX=M40fK2w=nm5bK zlrI$}D6JS3pu4zuGKMEi1?(FKo_q(mK1^tfM|0p*Gp>iQx8bO-xC**ij#Xy<%!qQ9 zqeEGxghUAATk8W5opaH-`+ak5#L^%O!%#J`c_*zfFR-hD;O*p-Vlf4C&BHBrA%lMj z4}yrz)Gr4l9&h;}{7fN{y^`=#VHcX4{)HFacEt>RChx8VGP0E%w|dr*ZFm{Y%1Jw9L%>K&_TGCv zba?dbQ4%l(A@m1bQsF%w5SwvJyq9@x@3pC0c*xhEj+^I<0<>HYS67~taJS4e;Ontc z9VEXkcyfY56$GV2Gx$69)|5!opvp{m7x*KAMDhcUl ztKZrkZbj>xXLm=A-$rR~zMtQ4!!^~;b=YbVGH#~|L|;sG0Fj9HBYifeL37*vkD0rF z(NGwiV;8Kt-kZdxCE3M*r?!O1$hh^B`58kp1^XxPP4^A)V|S;3Xq5W&UVdPNbI}U^ z&9P{xfihP-A3@}>5+@XKk_);c6w|T$Q5lr<(sEQ=sO#(HR(+|mgzyVQ^^-g!E^O(YXA z6+Okr%?yCdXDZ5+S9nId=~fn)Dbo(K1cP<7{06oO6Wv#}zIng6U>6`J%0- z%*Ba&pX&Z!Z{PjY)E9kwQ|LXSNKK@Q(gdVKf}nsXps4hsbm>))k^m|qN|PcTr6V1r zNQ)noBE2_((2>w~M#3OEB zN!sql)aZjf))U5qv&9OTuUj3qAOpH=iO&MfCYU^eq)*Vf7MIZXY!nk(PrsGFe(p!# zGrW98T~!zQJt#}G)%%#5mU#BN`ItTA_&7vz^l;l);|W6YZrdfWalen}#lcA!}DxTb*N88F%&5LI(vMj{N-+eD61#jYNa~rB510^!QR#9S=IAR zeBkm~eE%uQzeUzM2A|7HcsZ(`rUR&8`l$$zjlIjUl19HD(rXH(SzJ*59(c>s<(lWQ zA$DP$9hC$_l%uxGKys^BRn9i5kBZIQg4cuV=18BGRuA?9APqFQy^|6--+~y`16-rR zMnoZ5x%H^x{{4~+8nv162Qm<@_x!hkOO!@!3a?argk7MRT94{*zU`(p;63S@-NNzu zuMlqsZu~sK@me#dS<9WXI)GZ;sMSDqr-k=ryZ4M5ODunPKC905Z$lt&B6gC$6%jzY zK#TcKfWer5uK~+x)lM3v%lW@x>%+#R8-=)n}DKT#>O3MN2^PPp>zX!ak*Ewu>Cm}09bdWHlLrG?2^Q#HH0 zIO3ZA+}1;f9a)4~vMp?>>yCad!~QoEspU7@p9SaZzQ#dpT0ajn=5{kc%9+YXB^Cku zy{$!R|Id5%&DImP?;C`U^qGS{J`)cmpMaU8`^!~1YJO;^!Y-$#RvK;0IR}^T#OyscOZimGArbw!fc~x9xNKj1@HAWYgo(NdxEKiA>A7~6Mu*(TmTykaNlN8Z0@9HB&$&9>tlq(Z?5PVZ1e zz7eeiKlFoEOSmYN$)l?A9E`+W1Xll65p>7*L5IWUg+{@xt-r;5Dw@+Tar%uCVA@~X z%fAH>6-RdctNWSqeSvBpKJ0b?4guCIvV>jZ61~(q>+#@`-RKAbf zj%!N5C`hUW09Aj;3*BIK%q^ST(4=+Zh&q3DNT0d5ECB;ltm?Z%?F zW|5%N@2+Dl9qgW7HBNQzWk6`FqX6YJfV95cko^5h-!ebR>p2`kh~Kv9IyyXl^$}2H z^Y{~A#BV~@U6znz-FY^?bi6rZg=1t31I_KMY@g?p^9A}b>05dR{6q5pvP-5pA+7T* zWRS=5<8rjkMEfuU#qkm!oycJn(^E4p935;Eu5uR}TIObh2CYCM?!0j!E;zzCSVh5n zI4Xi=4Ju11AM`VZ9~IAUu(m1P1ctJ~WKh9HIWu>ct9Xq|sSdh=b*-{k{=0@eP}{x; z0%c(J9#PylS_|C;Bn@SPkKG>~( zp1QGg`DL29_^ZpHcDtF1CV=mNYAf^EW>myW82c|uh`J3_bTHr&K~${&$q!9GE?|Um zUNmam8Xp#u#Ly@a?3m6dQ67g+2Eq4wg(%G+%p9+mh}%xxtS*A=tUQfS|Oe}V@{S3x8n%w^&+ z;})IPtGUCtR%yofB6=bn^j7Pt%jc~(|EaSrH@DA)cn`ZeT6gOR-OB{202wJ#03ja#P3 zS7($qknbW5^}{N{^NQD%DgHnHLKwMnT3Vv&nls}s##d^hp>M$|&GP!ANq2G_ zi>9AQq*pr#H-7MXO3_hdp3vIsWmI(Zr!xe;tM-w)FNzhw;g@-VC7m9#h4xr}*5Q-9 zyqmfVENmrXgO(P@l69?)MB|-!mHN_o&oicfDSv}ObEF_czW;CxhOO4Pmpxj*3Na}9?;HthAWxDPCDlkQPg!DB2<4<1i|D-6=Pwjz zgG2hAXHjSW{TD1hdvL9BW&Qf*{)-ut6i2;@OUakMHvTN>k}R(k>*+VE%n=Z~_$X6) z7Gn`rDt;C6JfhvHOtsRUf@mnFMkO{uKl8P;+8%$(swDle7;6ozoAKx!^}|i!HwMZ= z(w1+Rsj(k0q zU)aiW>Qhrk6U9fVuAz4>lN#Ie`eu1P?<(i|s?H>3VX>vWne-gLadiqFaujuiwyLyx znEk$iv3X76(U*%S{HZ4HQIi|wx!Gh?hlz#L>`>Xz^R6oK>G%&HT$^CDffa2(S$kkK zFp;Np!#eVGJwD%4)Y=$jQnq^jrYNdvC^g#-{Y9m2eGHX~&6IW01`7+y%6+nSk!o+3 z^9PkzxtN$G`V~FzJ1%Y+DlH(BzuI;`>H<(@^L?-Z~B4F^jvMm_U~2ln%rXU@XSm`gt&5o`nyme z>?|*K5=n$y)`Hi-)>M`*9I!M0V&0{nq}|c^3M{1W%D`npdaOR&JEealm`qdQgR%-+=qs#YX3ke+r3|^0 z{TSl4QtnW1`2;uxSu#&pe5JHiDEtS8FRHn`sH9Rim z$R+iBQhNHOpK`_+`hrp!p71Mt-KbcGkC|7^{`-J3Pyxm0%bE)-Y>2exis_qP_{l@w zWqW^A!LB&wqqnFgnH4k8lCju$!pz*d<&fdJI*@} zeA5&0n!t%5#4>)f{$92nD`#hoIgW}HH0CHYwxv(gb9n5C{Ai~RbJeyd)P<_lRCZ6q zNI0asn$W=JtRCM^QKY_n2xG?3MKS1|;GOk}Xe&8~*)5anm&k>=^*-nQq|@>_hS#?= z(q?Bug(cE8xICaZ9)dK8G;w4kQ$73V=vW_lwmM=q2uAVaXh>oazFZ%kGHLtrOM{6I z?(n0!PUYCF)r2BJ!wCoo0Yi&0mvVk{k{buIL>y0xz2|x52;>?Hk&+mpjxI znD~+9`M;NPSXe=6jE{Vd^Y8T#K`Y*_oKR9>H{AC;{C!aVCVbf#5nOkEK2NdBVLm_E$vH2odx%xzkFiS- zWQeVyHu!P_W2x&`m<-Ktr^%};zH?W}G_Se1{n21Gnu+w@unIYAa7mLoRsWl|vsuI> z?5&^F*+*IrQOvog4n`BBOOr4`pyme_upua@((~dx5%&10&?_i70^nBdP$J!FMt2}8scfUVP(X&~4Mh9SDpg>rC8 zZGLQ|DZC!m8j{bu`a&~f|4jRkjXVD1phQu53A@tvXO`NWkpLyPut{u@tiQWpD52WXnK{sp)AwT@DBY(!O6%Q86$9oxj>S1HMglyR9I+ zaCTm-ljSWckc{zU=MfXVDF{6Lp7U%d{QRNxgnJS_Vpl!;(MgiG8JjQ&X^vXSApCdu9EJdh{Su8<%!D-D`_hpU`G1aR8;MffFR%* zBpoWn0|gO%*crV_4qnQ=rB9+k%wMGqo=>Tj$@JXo)>k%FB8t?afvb%HPBLOHEd?kn9Scq z@9@`Q&vc3(U;s|P2w{f4qSewK7C(nAKDY!r1r8QoRTifvv|?&u{)fFP1S+Wn_KP|e zzOPR-pW}1uK0lZe;2j#9x!xT2Y7*{yqdEeD5Og^2bogToTl&(c918?;39K_&A;d zWd(`RRItQ@a&@3rO|*0=U+HRm{O-y=LKrHW_RjMQokyN`7z<;mk-4IIh1w|QFfeA0 zl{WURt;N#3Oirzy{m469=6)s#6rt5M_(IK05p~E-G)%q&P^gsK(Q5b`j zy7V7@3Fa_sCGF??NIH-@TzU$LSiarX!CEZ|AR)fVI!1yZM=gGA?FRml;I+8VKaWF^6<}37yC9@G7;VRpsT= ztf4I=(4q`Ry6jMZxf>We4@k{+`?~lTq5)%8kim=r(Oc_~hUQ{%MC|{Ijkd8MGB|%`2`$UFCUs#5TJqXSn3Y ze#_a#>UG1J=Q|FY2KkO7+?dX4^az={2Tvvv{k!!}lI3R;!h7jtkW*j+`Iv#b+_jMY zg9_+vhH`+V6P69*y@V(Ie7Ecg98Nv{y65qb1EPZwH(^d;xmcuNRF+-I zSE18get4nH1z;oxg7~cigsd7G>9%c{z?{1KB3`}1Mlsq#NIc}YBtNJ14R!!|i_UEY zznR$XF1B!&!G&plCo`n{lW+FbUr z1z!@w{;icYYs<)9rIcKzjgtPLT+ZY8tNlIz~35r!0IV+K}!GZ0)hn_lPwN@f5rw*J-Oc|MiP}^PBXRC%&spq*opIqJc-+W zpbJ&Ec)`A+>p7GQe-wj?Sq6uBfj?bXaZbXkX>%F0o0KLWq)t|4X||FCF^4s;+%?!r zG*?)&gNh_{*Y1zgy`vFl8Q{PSmBTSRq{ST#eE^A{ztmFOr_BWdq}Hv?s0w9(RtuxL zwvvX1X2XiD?ZY~|B+zL@`P47*kF*_A0z;OulB1RNV( zg0nk+oZHFg$@1O%+;Ux!OMD?UZArL`$rhwF7V>rs8g6!)>FCj9C|&b^Y5}}e*M7bB zVNw9cmc{6#rG^ZKMJ# z+Qxm)jcl(Cvu}@JWW#>) z^pOgJHg(c=+%Gz_`y){u3b!Y9jJe0F!t>!v;fLq#dAj7Eyo0*;l~O)Xr&A%g#qY-} zC7XL6YDlW>j==wr3ebV9w2}M; zIsu1)@8VhWx1q3ZHhusNjmOaASrJUc@9s-yY@lf_6pqD|8tcMQ9il{fdi|N}?S_#j z*!V@)Z|dA&)%JD;p*>kTlvc^+aMff9;H0dyzAE~aN`fHN>EG$+y>dqh_EDWFnrhc&C zelu{}&K!QdC;yTgaYnU96N+39P=r*e=4RO-N`TV1LTsg;)sviQ>R+xES{Cs%k~_zE z1}K1IiQE@rMO~^fL^z!L!F|NUU*}!nNwS-VHQ18U6BOslwv*fa=ik!dBILRkD3Q`IqyGV4c|ZXv=J!tgWV#0nG6TS^A7UTq6phg z{Kj1EB`GUiFtP;l))|bk3w<~HbFeK%8?!YW4LMN17KY8LR^k!gxVV$kw;Wo@4+KRs z4FCbkEWU@|Nfg| zismi_d&GWwd$?1!km}yKuLad=&9Sr|VsK(2x&_baYDjFmJg0>I z>Y^FCt+O9Ae8#)e=zxH;$a8pC&55_n7PG?4{PUghZ2gLYn^*~foyCSvIw_k0UFsg9 zK$lA-MwPfN)iZ1t1t!y7KKsM+tvj-;8>(7KgL0mU!X259KglqNR~CJ z__D^Hn`h*+V8-JC?A#F*YFefeSaT4dxHBsu&30CMvY^(#s`8E&Rfa3*W#I}4nzU%n zh0eQzKzDJs-Dv#n%sxz^GlYDc86dhjkm)pOc=gn%eWx8xo0abgzJh8!R^k#B*%a&flaw{oMg%Dm~SRGQby{I%h zw-JCmctLU5LNagfu8%J(GQH2Egc579Z;EuMLt_AO?fo|^l<>s?F3d|o;H`}!MiWqm zvU*svMgl)fB`ed&$=?niVHhpep*z_2Pn4YMT&xq|sO zir*y)^@5Chdx$=Yv;%6+>gs}q{6A+!3Ls7ytH3)cv4T{l>wAMg=T+yV^Nax!Jg7q6 zX80a1h8Z{-ef$`<{qAmIiTRYW(ohL-HYMQYa?I@X+%4{hN6Ib@F1)oSC{8S0QG9un zWwnKT(8J&qNT@V(=nH#||3eCX-rKc1f?6@V+wLv9W#V7~+1{EvTT-<;naO}i*KFnR zHtxOTe~_Y9cVldPIPggq0;?vcV5=6?<)I?nd>$TeWQ?Gyuf2H^$6U*xixA_b`ave^53*|aMBIXP<)1SOPwxbnR`KcpzghdEI`RtSE43`gwRpxTJq*cN zB0>rmJ!Ct;QyF&JtMg%}v9z9Wr*przi#F>*XSaCZHsWu8*;!u|t_LLeV$yIvxB?VNk+g)w@@IL5;cI-uE_D?g6e{)~^0!I{@L9`XH9A=2L1Ld0_ zx#@N~4(qs&GI%Z$Y#OaL59W0vfIaB}cWg^eK?kLLrnTk^rHZB#*o%83*7gGxSID!y zNm2FRH+(KOFSGLfHgf-KVg#C06@>3{$Q24Omt@{*a5-E@@1rwM&{k8#qp_LErkt;f zvQq#1fmfnCZDZ*R70@D2uZ{@sk={o2R(h3 z8iLI^yb3AtFo8q*37|w1M*HZEriY_}lZu<|p!LEd9%CB%(=!c0>Qq)+E*V-VEkO5b z3*zbu#&9B0Ru|s=qiHg4gE5|$Jy;N+!V8*E13C66U0MYm*x$cgY7=jihF&3BD^Lr& zS4`9bsiS1>Zqe`XgZ$-^KnP!eAb{G_*r8Fh?tH_TtrvXG2qE=vIsc|74k9yYcFMD6 zIy;1HVZ(m;ov$1<1N z{d2Lpyk-^bsWE;#zCIz8Nzj4(2S%$4fc+rE9}Z7+Ur+Tp(W{WI5QastId^dnF>+_l z5hz}*EWgzL&;m4tv0DiucGPWla}l4Oj^koXkoSpeW*wk|Plwa-HkdzwH9E|^s=^}2 z%ya)m1QAPjlq>-Jt zX4I8p1~*)vr#6sWm@kZhTm}Y zKgsBo26O%1s9~?FG;VpVKT5+%m2o5M+-71jgIBl- zt#U*I4sWhc{uHPswL7P-_a4_<>h7xaCul*xL2O`jOrnxVtgaQbZk0u4fou^c)TQeXeGnndOC$n!l^gR!{?0J-1GiYCGc1sRs>IL3ctA(} zbZywoksqT#2Rsi2uv|bF00z8+T?2~DCls#dz=5ej4r~m7ROv3=F z4|2xa<(X>Y0tBO1QF&##1r?nhqArev0#KP2t=BMy%Gcv~lChmM=; zLeBr2$`7Z(TQgnO=f}Jlx5c!85YQbq6k^9&^+t>)h3EtU<-KRxGBG&)>i}M3Dg+4c z+O(gdm*NWnR)j{7sZc~(b>L$=%>=<8!oU<4=1vVb;nH$mJ@Z6DJG-f-y)i2A=iK;NHUL zSj{&JLnBky05X28Ecl>{BgFILOtP*r(^5S3!@yE+Cj&RJ3tvOu6dU0CEz!PoeazS= zKU$8Mom9tc)1e*CwiRG0fLP6BOkWXhx$3~VA3Nrm1X*hi3l_%A^^AYrG+y2<0gfEX zPh^m0bh;R3@eB)?&g`Ya{qqGCHmNmpj7u%m6f?%3&w&&RB^SSwKGA+@w_3?uRQ{E% z=b)NSVT}fV^6A8T2EO@T2$2oxIX#K|IgF-ADzv`KPem!DJJG6PeJT-OnT*WVHCmF5 zy}+eScJ7P3(xATdj=DnrBu`#$brAzopotb?t5DDC26xtVHyvEmgf^{D2ki2r4X!Az zUG0&l*_m+d5V#M+8Uoc67?&iMaq)5i6{3@qm3M*$GMNEh;%w@q zATLtAQ2F_q&XdHwsw#H6>=fkVPb#Z$J#=CL49*W4%otrkvCML{d|rflQ_xjk24b)y$w-{q>ji z!!yjPi30lu4*W@=gNd4(fFOdKAHa&xWsd~=9Ym|hppvI|?>zx9NO2&+4{qrM10~F7 zXWat{0@cCLF!aD?h#%U6&_Z;zJ<#`0L}4`mNl^sN9G=(me6SPNUp zc+>+Ars*YwXEJG_i02{uvu2rWaUK$(Ug7YI>R{ELgqE`m zbRCcja&=h%hFB%9ng1D`zSy>Wo8bBSH6`g@Efa{PHF%E4%o#VK_{PHB3_g(5ZYYD| ztAh?g7tx?2S}C%#1IoOETVi2jdOLD4i-q679J9{~GorVFO6|Wm%q`z75CgidEUaMr z$~HtQYQT<8t)-S{B5Q_KWf}HrZ>d7zjR5lzl>t0_0zGmGodHOZ54^>F6Zb;n1Tq!HPqUBk5p!vuwKZ?kx8d_@4Bx` zOF$@#`FB)A9DoMg9kEOItvOh~Zpep)3nDx-`aL$QIEVA_{?#Vi$B>W_HQt?7L$wy- zvq|DgS^!JXCaJ&CIi%>Ki1!0XgS=hWZSjU1%kQcEQEXzMsW}WpkS)8X9fqwn4O2L{ z^Tq2+v*9T`5SzN*wI2# z>H)%(&x8qhud#4jHN1nsxfn2bekK#vDn|~dO?SJ>$g!OW+s=)S7 z&w=XVW{WshJ<%mM$T`qM^2O}(`8+%$ay=arGJ&#ii{v|P=*I%$8FEHT}Zt>_r zodF&?Hpf#3^J9H}R8e=IQ@)(GsS&13f_D0g1sX7iG^jElQjYDQud+eLx&TBfpX&!g$^N1A0p2S zHY=!cSD#QzKoCp=tDgUvu1o)2fZgnD5G90gOI$=fKMf58!oWRbyFoc8i7fsb-!nl^) z85wjcVx~{;SNUj6FS56=_xvllnA}Y z8+SRIZ^1%mM+?4lg=S|F@)3DURHCoao`is`3}nytSgxkD%UCW`_!))h(A*Q=ZXkFt zZgrtLQ#_mqqTS#koG+|#*iF81G)hj;N#=>>xO>0qK`pl5Va)_74!WxBN30Jb42Jww z7!`i}&Cu2~;Bc$`dNPTQ_dL__atrodu;O3Y*zSMvExDCfzV?9=z#KMLPsWpXe~Dzi zyv%ec0m`L2vV<)gt5w7x)(eX+@!ZM{S6!696y6eAV^Um}73C=gnFu6rdcKLGw5dc1Ja(gfKnnEmf!S$s~_*yRFU)0-Z z#pwt#X7;|d{YjTdxG~{1h3t9=Pvs$(dQ9l2`65{7obNhCnyb9X|ASt24TYlm33P-6 zic+V;kBXFAqv?w<4#8bPb)ti&)tr>PwB_7_J7T|ml}Hz%q##c*R*>ds2d?nUzXd&K z%m*?>y@~o>O!uO#ign6t<%yBQKr*z(iUM!${7OMCq@PdcjAB@#z&+T1N;G4#QPZpM z5wn5Yt=p=E`DYgH&n;U3&8K(zM_Fw_*okq=N^>{U<{?Jp)L7ggIJ*nr%3x;8E~Ai{ zoFL-Wwhi*MzN&kl)zx%W8Q=G^dUK5dlM8HunDdjay4g9AZP&?X?~*Nul{0Sn+XbS@ zXo-I;rT4Cx?{-3dsJ}`kdh^$H>Kpsx>itAtwFRm3u&b}yo-WR-o`0cYv6~wI@No`B z&FnT^s}L_ww2HC?rlFNbnGB!N*4lc01@OZtNc7qUEqEuQ&Qc^QS@K4ksxRT~YQ@d9 z3p=8!+_s&XX0BUWzC7n=zrUs}$0f_@=(=bFBm0uA2h1UGtH%8;Ez5wdhBE^W=;rV1 zW!k0WGu18In(2*k8mGp8$@5|Gr4Uzh%H}rYht69Sd2jaqIa6RV=E9b~p7v{LZ2v8% zlN#($YD~LGqO3+Uhdmh~c$cz1D$sKhYQUL(TLC)2jkN)+YOh!R|1h{pk zeqIfuB&G&GBiL0HhL{#3@5s5$xost)&>lQ?EfmdaHI0%tE6la*?h}L6!OXI}mf_;& zQj13S(@yKsbuz_AF^n~QNVp3<2P}%s4}#MThM9(HL(*&qFetj@4x-i{xRL*-56APR=5gO z3}Wv0<6gkd*B75^gaJ#8KCVDhfLA`ln4JB`Z>Q~)L?MTDnB}tK6^EUdzv!b+Keq-f zMa(A+S=`a})=-m|MM>|> zwtsM5lL7dF3qih*Pj9r@?6ymt!()8XxHwZxv9sO>=lNReFspc|YCNx!g zniXdA=Pzo>`l+R#*_S8CF3q9aM3$=M(bsMRL`)dI}R{yUI>U8S%JCywX{Rch^Nj-?o7f{cm%8%Bo zM=vf_Ye=vpBwo6q>#ym4O+W*hPhO03L=bWqOsQKc?GyiaEs8LK9F=zB{$?Ozpo^5!;4KrGsN{LBdo1aR$4jBcBKeSt_--=WN8`xQi>+X%61YonM($lUKq0UsLLg*bT@NA;D>%6`RUEmA6$+V#PJ z7e=90IAp6hrtAAR`A;F9%&6Q_@k2)C1sWon_>tqGGZEgpS=~3{e!VY`5^;wj;D z1IM@hZ-FM5!&7P5msfSk1F`Ar+JB-~<?EWif|>Tr#e`ACtr#DF6?wHBIC z_+JWx;EUD&r9cU;HvfWaM+>VwPeG{5O&~%&7{@f#+jTwm7sm)UJoLOnKfvuwLp7{* zyc!3oIJ%JB>EPbf=Q0}Jp~ee(Fz4P*-s!hW$|AkY`8xz^O}4kl97ehQtNHkIs`kh6 ze{`+Z49J>x+Ocm(Dlp-T0^GhoODSnQe8UdH2q5f{%Ok3fKCA17*Y%W` zmRhL)J4(X?09a5*Q~ePId!KK2ei(2d<)J= zlCkAM^D;$kFJm2O(*GReSTf}%nF+3&^)GOkwRU~ zwio+Ae$3JsR5wPLs?%yv!J;K#d&cP!KmZ3VZf7N_!ujMlHq3*TA1Bx6_!d17q3l`K zzlSntE`_^t7+ZJ~lL65>+6W{xi<=Ei4PA>(66KG|AMZrh#+X?iW(2s literal 0 HcmV?d00001 diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index eaec51a21..baa4888a5 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.11.3", "fabric": "*", - "minecraft": "1.17.x" + "minecraft": ">=1.17.1" } } From 38539c214866970e107813b3091d80c1557d2aa5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Jul 2021 09:37:51 -0400 Subject: [PATCH 069/100] Exclude Google libraries from the built jar --- bootstrap/fabric/build.gradle | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 65dccb9a1..fa38820b4 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -28,7 +28,11 @@ dependencies { // You may need to force-disable transitiveness on them. implementation 'org.geysermc:connector:1.4.1-SNAPSHOT' - shadow 'org.geysermc:connector:1.4.1-SNAPSHOT' + shadow('org.geysermc:connector:1.4.1-SNAPSHOT') { + exclude group: 'com.google.guava', module: "guava" + exclude group: 'com.google.code.gson', module: "gson" + exclude group: 'org.slf4j' + } } repositories { @@ -79,7 +83,6 @@ shadowJar { relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") relocate("org.objectweb.asm", "org.geysermc.relocate.asm") relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 - relocate("com.google", "org.geysermc.relocate.google") } jar { From 7f21a68d8d54e9573098fc9f35f8fcc6bc139145 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 28 Jul 2021 19:53:08 -0400 Subject: [PATCH 070/100] Auth type refactor in internal config (#26) --- bootstrap/fabric/README.md | 2 +- .../java/org/geysermc/platform/fabric/GeyserFabricMod.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index 26cb55da7..e5129111a 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -1,6 +1,6 @@ # Geyser-Fabric -[![forthebadge made-with-java](https://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) +[![forthebadge made-with-java](https://forthebadge.com/images/badges/made-with-java.svg)](https://java.com/) Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/java-1.17/) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 412ae860c..0ff2a0123 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -40,6 +40,7 @@ import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.GeyserCommand; +import org.geysermc.connector.common.AuthType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.network.translators.world.WorldManager; @@ -145,13 +146,13 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate"); boolean floodgatePresent = floodgate.isPresent(); - if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !floodgatePresent) { + if (geyserConfig.getRemote().getAuthType() == AuthType.FLOODGATE && !floodgatePresent) { geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); return; } else if (geyserConfig.isAutoconfiguredRemote() && floodgatePresent) { // Floodgate installed means that the user wants Floodgate authentication geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType("floodgate"); + geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); } geyserConfig.loadFloodgate(this, floodgate.orElse(null)); From fda17077a067d49220f0607eecb69e5a6a785d81 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:27:13 -0400 Subject: [PATCH 071/100] Bump Geyser version to 1.4.2-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index fa38820b4..ef27515b9 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.4.1-SNAPSHOT' - shadow('org.geysermc:connector:1.4.1-SNAPSHOT') { + implementation 'org.geysermc:connector:1.4.2-SNAPSHOT' + shadow('org.geysermc:connector:1.4.2-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index fbbf18cd3..592886b18 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.17.1 yarn_mappings=1.17.1+build.14 loader_version=0.11.6 # Mod Properties -mod_version=1.4.0-SNAPSHOT +mod_version=1.4.2-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From cef3f5f1bdab1758620d0e753ff3b45140a8a4f3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 22 Sep 2021 13:51:06 -0400 Subject: [PATCH 072/100] Update to 1.4.3-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index ef27515b9..0a3893799 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.4.2-SNAPSHOT' - shadow('org.geysermc:connector:1.4.2-SNAPSHOT') { + implementation 'org.geysermc:connector:1.4.3-SNAPSHOT' + shadow('org.geysermc:connector:1.4.3-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 592886b18..f33e6ade1 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.17.1 yarn_mappings=1.17.1+build.14 loader_version=0.11.6 # Mod Properties -mod_version=1.4.2-SNAPSHOT +mod_version=1.4.3-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From 6cc092cc8e9759b7643bb6b16ffabbfc5d6cd3a4 Mon Sep 17 00:00:00 2001 From: byquanton <32410361+byquanton@users.noreply.github.com> Date: Sat, 9 Oct 2021 18:47:10 +0000 Subject: [PATCH 073/100] Fixed loadFloodgate method (#31) Upstream Commit 7cd3eb99ef2e44e8ac2cc4741df2d3ca9ced5946 broke it --- .../geysermc/platform/fabric/GeyserFabricConfiguration.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java index f3b446760..e0ee61aa5 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java @@ -32,7 +32,6 @@ import org.geysermc.connector.FloodgateKeyLoader; import org.geysermc.connector.configuration.GeyserJacksonConfiguration; import java.nio.file.Path; -import java.util.Optional; public class GeyserFabricConfiguration extends GeyserJacksonConfiguration { @JsonIgnore @@ -40,9 +39,9 @@ public class GeyserFabricConfiguration extends GeyserJacksonConfiguration { public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) { Path geyserDataFolder = geyser.getConfigFolder(); - Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate"); + Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null; - floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger()); + floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger()); } @Override From 29fa4a9443886b1e2c00e3355326f106224d5490 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 27 Oct 2021 18:59:42 -0400 Subject: [PATCH 074/100] Relocate Jackson dependency --- bootstrap/fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0a3893799..002cc1117 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -83,6 +83,7 @@ shadowJar { relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") relocate("org.objectweb.asm", "org.geysermc.relocate.asm") relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 + relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson") } jar { From 3f88f20272ee0a663f77d9e3be8614771045f328 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 31 Oct 2021 19:46:51 -0400 Subject: [PATCH 075/100] Refactor perms and upstream (#35) * refactor permissions * upstream * remove shutdown from the command list * make FabricWorldManager#getPlayer() private --- .../platform/fabric/GeyserFabricMod.java | 28 ++++++++++----- .../fabric/GeyserFabricPermissions.java | 7 ++++ .../fabric/command/FabricCommandSender.java | 15 ++++++++ .../command/GeyserFabricCommandExecutor.java | 35 ++++++++++++++----- .../world/GeyserFabricWorldManager.java | 21 ++++++++++- .../fabric/src/main/resources/permissions.yml | 6 ++-- 6 files changed, 93 insertions(+), 19 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 0ff2a0123..339c5a9e9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -67,9 +67,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private GeyserConnector connector; private Path dataFolder; - private List playerCommands; private MinecraftServer server; + /** + * Commands that don't require any permission level to ran + */ + private List playerCommands; + private final List commandExecutors = new ArrayList<>(); + private GeyserFabricCommandManager geyserCommandManager; private GeyserFabricConfiguration geyserConfig; private GeyserFabricLogger geyserLogger; @@ -167,14 +172,17 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { // Start command building // Set just "geyser" as the help command - LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser") - .executes(new GeyserFabricCommandExecutor(connector, connector.getCommandManager().getCommands().get("help"), - !playerCommands.contains("help"))); + GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(connector, + connector.getCommandManager().getCommands().get("help"), !playerCommands.contains("help")); + commandExecutors.add(helpExecutor); + LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser").executes(helpExecutor); + + // Register all subcommands as valid for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { - // Register all subcommands as valid - builder.then(net.minecraft.server.command.CommandManager.literal( - command.getKey()).executes(new GeyserFabricCommandExecutor(connector, command.getValue(), - !playerCommands.contains(command.getKey())))); + GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(connector, command.getValue(), + !playerCommands.contains(command.getKey())); + commandExecutors.add(executor); + builder.then(net.minecraft.server.command.CommandManager.literal(command.getKey()).executes(executor)); } server.getCommandManager().getDispatcher().register(builder); } @@ -258,6 +266,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return file; } + public List getCommandExecutors() { + return commandExecutors; + } + public static GeyserFabricMod getInstance() { return instance; } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java index 1a446bca6..fc08b052a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java @@ -25,6 +25,7 @@ package org.geysermc.platform.fabric; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -34,6 +35,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class GeyserFabricPermissions { + /** + * The minimum permission level a command source must have in order for it to run commands that are restricted + */ + @JsonIgnore + public static final int RESTRICTED_MIN_LEVEL = 2; + @JsonProperty("commands") private String[] commands; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index d49a07625..1dbec0492 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -31,6 +31,7 @@ import net.minecraft.text.LiteralText; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.ChatColor; +import org.geysermc.platform.fabric.GeyserFabricMod; public class FabricCommandSender implements CommandSender { @@ -58,4 +59,18 @@ public class FabricCommandSender implements CommandSender { public boolean isConsole() { return !(source.getEntity() instanceof ServerPlayerEntity); } + + @Override + public boolean hasPermission(String s) { + // Mostly copied from fabric's world manager since the method there takes a GeyserSession + + // Workaround for our commands because fabric doesn't have native permissions + for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { + if (executor.getCommand().getPermission().equals(s)) { + return executor.canRun(source); + } + } + + return false; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index a8469364f..bd2cdcad2 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -35,6 +35,7 @@ import org.geysermc.connector.common.ChatColor; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.GeyserFabricPermissions; public class GeyserFabricCommandExecutor extends CommandExecutor implements Command { @@ -50,11 +51,22 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm this.requiresPermission = requiresPermission; } + /** + * Determine whether or not a command source is allowed to run a given executor. + * + * @param source The command source attempting to run the command + * @return True if the command source is allowed to + */ + public boolean canRun(ServerCommandSource source) { + return !requiresPermission() || source.hasPermissionLevel(GeyserFabricPermissions.RESTRICTED_MIN_LEVEL); + } + @Override public int run(CommandContext context) { ServerCommandSource source = (ServerCommandSource) context.getSource(); FabricCommandSender sender = new FabricCommandSender(source); - if (requiresPermission && !source.hasPermissionLevel(2)) { + GeyserSession session = getGeyserSession(sender); + if (!canRun(source)) { sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } @@ -62,15 +74,22 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm GeyserFabricMod.getInstance().setReloading(true); } - GeyserSession session = null; - if (command.isBedrockOnly()) { - session = getGeyserSession(sender); - if (session == null) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); - return 0; - } + if (command.isBedrockOnly() && session == null) { + sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + return 0; } command.execute(session, sender, new String[0]); return 0; } + + public GeyserCommand getCommand() { + return command; + } + + /** + * Returns whether the command requires permission level of {@link GeyserFabricPermissions#RESTRICTED_MIN_LEVEL} or higher to be ran + */ + public boolean requiresPermission() { + return requiresPermission; + } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index dd0d629c8..412266bb4 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -42,6 +42,8 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.utils.BlockEntityUtils; +import org.geysermc.platform.fabric.GeyserFabricMod; +import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import java.util.ArrayList; import java.util.List; @@ -63,7 +65,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { Runnable lecternGet = () -> { // Mostly a reimplementation of Spigot lectern support - PlayerEntity player = server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + PlayerEntity player = getPlayer(session); if (player != null) { BlockEntity blockEntity = player.world.getBlockEntity(new BlockPos(x, y, z)); if (!(blockEntity instanceof LecternBlockEntity lectern)) { @@ -119,4 +121,21 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { } return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); } + + @Override + public boolean hasPermission(GeyserSession session, String permission) { + + // Workaround for our commands because fabric doesn't have native permissions + for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { + if (executor.getCommand().getPermission().equals(permission)) { + return executor.canRun(getPlayer(session).getCommandSource()); + } + } + + return false; + } + + private PlayerEntity getPlayer(GeyserSession session) { + return server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + } } diff --git a/bootstrap/fabric/src/main/resources/permissions.yml b/bootstrap/fabric/src/main/resources/permissions.yml index a51d3169a..8a995f8dc 100644 --- a/bootstrap/fabric/src/main/resources/permissions.yml +++ b/bootstrap/fabric/src/main/resources/permissions.yml @@ -1,10 +1,12 @@ # Uncomment any commands that you wish to be run by clients # Commented commands require an OP permission of 2 or greater commands: -# - dump - help + - advancements + - statistics + - settings - offhand # - list # - reload -# - shutdown # - version +# - dump \ No newline at end of file From 4f44fa83582307507e889fcd7c75e3024e5451bd Mon Sep 17 00:00:00 2001 From: Akashii Kun <44606942+AkashiiKun@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:08:25 +0000 Subject: [PATCH 076/100] Java-1.18 (WIP) (#43) --- bootstrap/fabric/.gitignore | 4 +-- bootstrap/fabric/build.gradle | 12 +++---- bootstrap/fabric/gradle.properties | 8 ++--- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../fabric/GeyserFabricConfiguration.java | 4 +-- .../platform/fabric/GeyserFabricDumpInfo.java | 4 +-- .../platform/fabric/GeyserFabricLogger.java | 2 +- .../platform/fabric/GeyserFabricMod.java | 34 +++++++++---------- .../fabric/command/FabricCommandSender.java | 10 +++--- .../command/GeyserFabricCommandExecutor.java | 18 +++++----- .../command/GeyserFabricCommandManager.java | 6 ++-- .../mixin/client/IntegratedServerMixin.java | 6 ++-- .../world/GeyserFabricWorldManager.java | 10 +++--- 13 files changed, 60 insertions(+), 60 deletions(-) diff --git a/bootstrap/fabric/.gitignore b/bootstrap/fabric/.gitignore index 4215ddd83..0a48ed373 100644 --- a/bootstrap/fabric/.gitignore +++ b/bootstrap/fabric/.gitignore @@ -15,6 +15,7 @@ local.properties .loadpath .recommenders + # External tool builders .externalToolBuilders/ @@ -134,6 +135,7 @@ hs_err_pid* # Gradle .idea/**/gradle.xml .idea/**/libraries +/.gradle/ # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, @@ -235,5 +237,3 @@ nbdist/ # End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode -### Geyser ### -run/ diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 002cc1117..0e3331f98 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -1,15 +1,15 @@ plugins { - id 'fabric-loom' version '0.8-SNAPSHOT' + id 'fabric-loom' version '0.10-SNAPSHOT' id 'maven-publish' - id 'com.github.johnrengelman.shadow' version '6.1.0' + id 'com.github.johnrengelman.shadow' version '7.0.0' id 'java' } apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'java' -sourceCompatibility = JavaVersion.VERSION_16 -targetCompatibility = JavaVersion.VERSION_16 +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 archivesBaseName = project.archives_base_name version = project.mod_version @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:connector:1.4.3-SNAPSHOT' - shadow('org.geysermc:connector:1.4.3-SNAPSHOT') { + implementation 'org.geysermc:core:2.0.0-SNAPSHOT' + shadow('org.geysermc:core:2.0.0-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index f33e6ade1..6f3a0e059 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.17.1 -yarn_mappings=1.17.1+build.14 -loader_version=0.11.6 +minecraft_version=1.18 +yarn_mappings=1.18+build.1 +loader_version=0.12.8 # Mod Properties mod_version=1.4.3-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.37.0+1.17 +fabric_version=0.43.1+1.18 diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties index 0f80bbf51..e750102e0 100644 --- a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties +++ b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java index e0ee61aa5..b49707871 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java @@ -28,8 +28,8 @@ package org.geysermc.platform.fabric; import com.fasterxml.jackson.annotation.JsonIgnore; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; -import org.geysermc.connector.FloodgateKeyLoader; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import org.geysermc.geyser.FloodgateKeyLoader; +import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import java.nio.file.Path; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java index 26979d6da..e3997da51 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java @@ -29,8 +29,8 @@ import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.server.MinecraftServer; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.dump.BootstrapDumpInfo; +import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.text.AsteriskSerializer; import java.util.ArrayList; import java.util.List; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java index 40e18e43b..9c85a21f2 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java @@ -27,7 +27,7 @@ package org.geysermc.platform.fabric; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.geysermc.connector.GeyserLogger; +import org.geysermc.geyser.GeyserLogger; public class GeyserFabricLogger implements GeyserLogger { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 339c5a9e9..904d13d40 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -35,19 +35,19 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import org.apache.logging.log4j.LogManager; import org.geysermc.common.PlatformType; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.GeyserLogger; -import org.geysermc.connector.bootstrap.GeyserBootstrap; -import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.geysermc.connector.network.translators.world.WorldManager; -import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; -import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; +import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.util.FileUtils; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; import org.geysermc.platform.fabric.world.GeyserFabricWorldManager; @@ -65,7 +65,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private boolean reloading; - private GeyserConnector connector; + private GeyserImpl connector; private Path dataFolder; private MinecraftServer server; @@ -106,7 +106,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { File permissionsFile = fileOrCopiedFromResource(dataFolder.resolve("permissions.yml").toFile(), "permissions.yml"); this.playerCommands = Arrays.asList(FileUtils.loadConfig(permissionsFile, GeyserFabricPermissions.class).getCommands()); } catch (IOException ex) { - LogManager.getLogger("geyser-fabric").error(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); + LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); return; } @@ -152,7 +152,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate"); boolean floodgatePresent = floodgate.isPresent(); if (geyserConfig.getRemote().getAuthType() == AuthType.FLOODGATE && !floodgatePresent) { - geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); return; } else if (geyserConfig.isAutoconfiguredRemote() && floodgatePresent) { // Floodgate installed means that the user wants Floodgate authentication @@ -162,7 +162,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { geyserConfig.loadFloodgate(this, floodgate.orElse(null)); - this.connector = GeyserConnector.start(PlatformType.FABRIC, this); + this.connector = GeyserImpl.start(PlatformType.FABRIC, this); this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index 1dbec0492..1fa9f55ae 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -28,9 +28,9 @@ package org.geysermc.platform.fabric.command; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.LiteralText; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.common.ChatColor; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.platform.fabric.GeyserFabricMod; public class FabricCommandSender implements CommandSender { @@ -42,7 +42,7 @@ public class FabricCommandSender implements CommandSender { } @Override - public String getName() { + public String name() { return source.getName(); } @@ -51,7 +51,7 @@ public class FabricCommandSender implements CommandSender { if (source.getEntity() instanceof ServerPlayerEntity) { ((ServerPlayerEntity) source.getEntity()).sendMessage(new LiteralText(message), false); } else { - GeyserConnector.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); + GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index bd2cdcad2..c1d8ebc29 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -28,12 +28,12 @@ package org.geysermc.platform.fabric.command; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import net.minecraft.server.command.ServerCommandSource; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandExecutor; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.CommandExecutor; +import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.GeyserFabricPermissions; @@ -45,7 +45,7 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm */ private final boolean requiresPermission; - public GeyserFabricCommandExecutor(GeyserConnector connector, GeyserCommand command, boolean requiresPermission) { + public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command, boolean requiresPermission) { super(connector); this.command = command; this.requiresPermission = requiresPermission; @@ -67,7 +67,7 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm FabricCommandSender sender = new FabricCommandSender(source); GeyserSession session = getGeyserSession(sender); if (!canRun(source)) { - sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); + sender.sendMessage(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } if (this.command.getName().equals("reload")) { @@ -75,7 +75,7 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm } if (command.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); return 0; } command.execute(session, sender, new String[0]); diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java index d6180e7ec..d548aa823 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java @@ -25,12 +25,12 @@ package org.geysermc.platform.fabric.command; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandManager; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.CommandManager; public class GeyserFabricCommandManager extends CommandManager { - public GeyserFabricCommandManager(GeyserConnector connector) { + public GeyserFabricCommandManager(GeyserImpl connector) { super(connector); } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java index 0a3f17f68..1fc945f28 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -32,7 +32,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.text.LiteralText; import net.minecraft.world.GameMode; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.GeyserServerPortGetter; import org.spongepowered.asm.mixin.Final; @@ -56,9 +56,9 @@ public class IntegratedServerMixin implements GeyserServerPortGetter { // If the LAN is opened, starts Geyser. GeyserFabricMod.getInstance().startGeyser((MinecraftServer) (Object) this); // Ensure player locale has been loaded, in case it's different from Java system language - LanguageUtils.loadGeyserLocale(this.client.options.language); + GeyserLocale.loadGeyserLocale(this.client.options.language); // Give indication that Geyser is loaded - this.client.player.sendMessage(new LiteralText(LanguageUtils.getPlayerLocaleString("geyser.core.start", + this.client.player.sendMessage(new LiteralText(GeyserLocale.getPlayerLocaleString("geyser.core.start", this.client.options.language, "localhost", String.valueOf(this.lanPort))), false); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index 412266bb4..5a66f6ae8 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -38,10 +38,10 @@ import net.minecraft.item.WrittenBookItem; import net.minecraft.nbt.NbtList; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator; -import org.geysermc.connector.network.translators.world.GeyserWorldManager; -import org.geysermc.connector.utils.BlockEntityUtils; +import org.geysermc.geyser.level.GeyserWorldManager; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; +import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; @@ -115,7 +115,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { }; if (isChunkLoad) { // Hacky hacks to allow lectern loading to be delayed - session.getConnector().getGeneralThreadPool().schedule(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS); + session.scheduleInEventLoop(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS); } else { server.execute(lecternGet); } From 5089067e4d3e957db63f514e09e69cd8ce3d2777 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 Dec 2021 11:10:22 -0500 Subject: [PATCH 077/100] Bump version to 2.0.0-SNAPSHOT; update Gradle wrapper --- bootstrap/fabric/.gitignore | 3 +- bootstrap/fabric/gradle.properties | 2 +- .../fabric/gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59536 bytes bootstrap/fabric/gradlew | 269 +++++++++++------- bootstrap/fabric/gradlew.bat | 21 +- 5 files changed, 165 insertions(+), 130 deletions(-) diff --git a/bootstrap/fabric/.gitignore b/bootstrap/fabric/.gitignore index 0a48ed373..06b9cccc4 100644 --- a/bootstrap/fabric/.gitignore +++ b/bootstrap/fabric/.gitignore @@ -15,7 +15,6 @@ local.properties .loadpath .recommenders - # External tool builders .externalToolBuilders/ @@ -237,3 +236,5 @@ nbdist/ # End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode +### Geyser ### +run/ \ No newline at end of file diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 6f3a0e059..66fbe3cad 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.18 yarn_mappings=1.18+build.1 loader_version=0.12.8 # Mod Properties -mod_version=1.4.3-SNAPSHOT +mod_version=2.0.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18328 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 Y(TzS~Xdo8@nTUZrK}a{fL*HNQe=4o%4FCWD delta 17568 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/bootstrap/fabric/gradlew.bat b/bootstrap/fabric/gradlew.bat index a9f778a7a..ac1b06f93 100644 --- a/bootstrap/fabric/gradlew.bat +++ b/bootstrap/fabric/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From fafdf31fa5598d9e130a1c16d8c48a0fd333ecb8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 Dec 2021 11:14:12 -0500 Subject: [PATCH 078/100] Update Jenkinsfile --- bootstrap/fabric/Jenkinsfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 24a90026a..72eb575a0 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -2,7 +2,7 @@ pipeline { agent any tools { gradle 'Gradle 7' - jdk 'Java 16' + jdk 'Java 17' } parameters{ @@ -28,8 +28,7 @@ pipeline { stage ('Deploy') { when { anyOf { - branch "java-1.16" - branch "java-1.17" + branch "java-1.18" } } From 257e04fa6faed2d519fc0c3d7e90d48e4fd085b3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 Dec 2021 11:32:57 -0500 Subject: [PATCH 079/100] Comment out deploying; we shouldn't need it here --- bootstrap/fabric/Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 72eb575a0..15df47de1 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { jdk 'Java 17' } - parameters{ + parameters { booleanParam(defaultValue: false, description: 'Skip Discord notification', name: 'SKIP_DISCORD') } @@ -25,7 +25,7 @@ pipeline { } } - stage ('Deploy') { + /*stage ('Deploy') { when { anyOf { branch "java-1.18" @@ -56,7 +56,7 @@ pipeline { serverId: "opencollab-artifactory" ) } - } + }*/ } post { From dd632ef4b19a52e99107eec77334efe2cac4a9f8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 3 Dec 2021 11:08:05 -0500 Subject: [PATCH 080/100] Update for Geyser usage This fixes https://github.com/GeyserMC/Floodgate-Fabric/issues/7 on the Geyser-Fabric end. Floodgate-Fabric still needs to be fixed. --- .../platform/fabric/GeyserFabricMod.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 904d13d40..3c175896f 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -51,6 +51,7 @@ import org.geysermc.geyser.util.FileUtils; import org.geysermc.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.platform.fabric.command.GeyserFabricCommandManager; import org.geysermc.platform.fabric.world.GeyserFabricWorldManager; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileOutputStream; @@ -66,6 +67,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private boolean reloading; private GeyserImpl connector; + private ModContainer mod; private Path dataFolder; private MinecraftServer server; @@ -84,6 +86,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @Override public void onInitialize() { instance = this; + mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow(); this.onEnable(); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { @@ -94,6 +97,8 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @Override public void onEnable() { + GeyserLocale.init(this); + dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric"); if (!dataFolder.toFile().exists()) { //noinspection ResultOfMethodCallIgnored @@ -101,7 +106,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { } try { File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", - (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); + (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); File permissionsFile = fileOrCopiedFromResource(dataFolder.resolve("permissions.yml").toFile(), "permissions.yml"); this.playerCommands = Arrays.asList(FileUtils.loadConfig(permissionsFile, GeyserFabricPermissions.class).getCommands()); @@ -238,6 +243,21 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { return this.server.getVersion(); } + @Nullable + @Override + public InputStream getResourceOrNull(String resource) { + // We need to handle this differently, because Fabric shares the classloader across multiple mods + Path path = this.mod.getPath(resource); + + try { + return path.getFileSystem() + .provider() + .newInputStream(path); + } catch (IOException e) { + return null; + } + } + public void setReloading(boolean reloading) { this.reloading = reloading; } @@ -247,7 +267,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { //noinspection ResultOfMethodCallIgnored file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); - InputStream input = GeyserFabricMod.class.getResourceAsStream("/" + name); // resources need leading "/" prefix + InputStream input = getResource(name); byte[] bytes = new byte[input.available()]; From 91095beb521c84fd886f8332e2026dda64426243 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 28 Dec 2021 11:14:30 -0500 Subject: [PATCH 081/100] Attempt to re-enable publishing --- bootstrap/fabric/Jenkinsfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index 15df47de1..e10609a77 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -25,7 +25,7 @@ pipeline { } } - /*stage ('Deploy') { + stage ('Deploy') { when { anyOf { branch "java-1.18" @@ -42,6 +42,8 @@ pipeline { rtGradleResolver( id: "GRADLE_RESOLVER", serverId: "opencollab-artifactory", + releaseRepo: "maven-deploy-release", + snapshotRepo: "maven-deploy-snapshot" ) rtGradleRun ( usesPlugin: false, @@ -56,7 +58,7 @@ pipeline { serverId: "opencollab-artifactory" ) } - }*/ + } } post { From 51c77fe808d93e5c938c62583e09cfbb09bacd5b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 28 Dec 2021 11:33:24 -0500 Subject: [PATCH 082/100] Remove invalid params --- bootstrap/fabric/Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile index e10609a77..c3632a8ce 100644 --- a/bootstrap/fabric/Jenkinsfile +++ b/bootstrap/fabric/Jenkinsfile @@ -41,9 +41,7 @@ pipeline { ) rtGradleResolver( id: "GRADLE_RESOLVER", - serverId: "opencollab-artifactory", - releaseRepo: "maven-deploy-release", - snapshotRepo: "maven-deploy-snapshot" + serverId: "opencollab-artifactory" ) rtGradleRun ( usesPlugin: false, From dcb91f34b87ceb075386539020a3b280eac1264e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:55:08 -0500 Subject: [PATCH 083/100] Bump to 2.0.1-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0e3331f98..cd8b811a7 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:core:2.0.0-SNAPSHOT' - shadow('org.geysermc:core:2.0.0-SNAPSHOT') { + implementation 'org.geysermc:core:2.0.1-SNAPSHOT' + shadow('org.geysermc:core:2.0.1-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 66fbe3cad..145395648 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.18 yarn_mappings=1.18+build.1 loader_version=0.12.8 # Mod Properties -mod_version=2.0.0-SNAPSHOT +mod_version=2.0.1-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From 5a5b2794a5120f9d290794783d05c7a46ff76bd6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Feb 2022 10:19:13 -0500 Subject: [PATCH 084/100] Bump to 2.0.2-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index cd8b811a7..1d09511e0 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:core:2.0.1-SNAPSHOT' - shadow('org.geysermc:core:2.0.1-SNAPSHOT') { + implementation 'org.geysermc:core:2.0.2-SNAPSHOT' + shadow('org.geysermc:core:2.0.2-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 145395648..feafc93ce 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.18 yarn_mappings=1.18+build.1 loader_version=0.12.8 # Mod Properties -mod_version=2.0.1-SNAPSHOT +mod_version=2.0.2-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From 3e71e3fb0b860d1faa197927b1c7b6bdd1c4a6e7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Feb 2022 14:30:00 -0500 Subject: [PATCH 085/100] Require 1.18.2 --- bootstrap/fabric/gradle.properties | 4 ++-- .../mixin/server/MinecraftDedicatedServerMixin.java | 9 ++++----- bootstrap/fabric/src/main/resources/fabric.mod.json | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index feafc93ce..31b3c82dd 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.18 -yarn_mappings=1.18+build.1 +minecraft_version=1.18.2 +yarn_mappings=1.18.2+build.1 loader_version=0.12.8 # Mod Properties mod_version=2.0.2-SNAPSHOT diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java index f5e9a121d..e30181f00 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -29,15 +29,14 @@ import com.mojang.authlib.GameProfileRepository; import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.datafixers.DataFixer; import net.minecraft.resource.ResourcePackManager; -import net.minecraft.resource.ServerResourceManager; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.SaveLoader; import net.minecraft.server.WorldGenerationProgressListenerFactory; import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.util.UserCache; -import net.minecraft.util.registry.DynamicRegistryManager; -import net.minecraft.world.SaveProperties; import net.minecraft.world.level.storage.LevelStorage; import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import java.net.Proxy; @@ -45,8 +44,8 @@ import java.net.Proxy; @Mixin(MinecraftDedicatedServer.class) public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter { // Constructor to compile - public MinecraftDedicatedServerMixin(Thread thread, DynamicRegistryManager.Impl impl, LevelStorage.Session session, SaveProperties saveProperties, ResourcePackManager resourcePackManager, Proxy proxy, DataFixer dataFixer, ServerResourceManager serverResourceManager, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { - super(thread, impl, session, saveProperties, resourcePackManager, proxy, dataFixer, serverResourceManager, minecraftSessionService, gameProfileRepository, userCache, worldGenerationProgressListenerFactory); + public MinecraftDedicatedServerMixin(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, @Nullable MinecraftSessionService sessionService, @Nullable GameProfileRepository gameProfileRepo, @Nullable UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { + super(serverThread, session, dataPackManager, saveLoader, proxy, dataFixer, sessionService, gameProfileRepo, userCache, worldGenerationProgressListenerFactory); } @Override diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index baa4888a5..54478f150 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.11.3", "fabric": "*", - "minecraft": ">=1.17.1" + "minecraft": ">=1.18.2" } } From 05f7b01540a1ab5f3585d96c97098a130baa54b8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 4 Mar 2022 22:23:58 -0500 Subject: [PATCH 086/100] Relocate Adventure --- bootstrap/fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 1d09511e0..0c2735eb6 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -84,6 +84,7 @@ shadowJar { relocate("org.objectweb.asm", "org.geysermc.relocate.asm") relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson") + relocate("net.kyori", "org.geysermc.relocate.kyori") } jar { From d4b19616620b8b302c068bfaf0161ca651dba35e Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sat, 12 Mar 2022 16:45:25 +0100 Subject: [PATCH 087/100] Update download link to 1.18 (#47) --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index e5129111a..ef83f6db7 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -2,7 +2,7 @@ [![forthebadge made-with-java](https://forthebadge.com/images/badges/made-with-java.svg)](https://java.com/) -Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.17/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/java-1.17/) +Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.18/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/java-1.18/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) From 5ab69522782f71c422d334d47f214fc90790de6d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 19 Apr 2022 10:36:22 -0400 Subject: [PATCH 088/100] Update to 2.0.3-SNAPSHOT --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 0c2735eb6..112760009 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:core:2.0.2-SNAPSHOT' - shadow('org.geysermc:core:2.0.2-SNAPSHOT') { + implementation 'org.geysermc:core:2.0.3-SNAPSHOT' + shadow('org.geysermc:core:2.0.3-SNAPSHOT') { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 31b3c82dd..1d9b12e67 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.18.2 yarn_mappings=1.18.2+build.1 loader_version=0.12.8 # Mod Properties -mod_version=2.0.2-SNAPSHOT +mod_version=2.0.3-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From 4b4529c590aedcb6c5577aac2de673048229c072 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 16 May 2022 13:26:53 -0400 Subject: [PATCH 089/100] Prevent NPE with new language overrides --- .../java/org/geysermc/platform/fabric/GeyserFabricMod.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 3c175896f..f6a657bba 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -97,13 +97,15 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @Override public void onEnable() { - GeyserLocale.init(this); - dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric"); if (!dataFolder.toFile().exists()) { //noinspection ResultOfMethodCallIgnored dataFolder.toFile().mkdir(); } + + // Init dataFolder first as local language overrides call getConfigFolder() + GeyserLocale.init(this); + try { File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); From 2a89eab100976db1affecf78dba2d5e53e3edd10 Mon Sep 17 00:00:00 2001 From: David Choo Date: Tue, 7 Jun 2022 20:10:12 -0400 Subject: [PATCH 090/100] Update for Java 1.19 and Geyser 2.0.4-SNAPSHOT (#53) * Update for 1.19 and 2.0.4-SNAPSHOT * Use mod version in Geyser dependency --- bootstrap/fabric/build.gradle | 8 ++++---- bootstrap/fabric/gradle.properties | 12 ++++++------ .../platform/fabric/command/FabricCommandSender.java | 4 ++-- .../fabric/mixin/client/IntegratedServerMixin.java | 4 ++-- .../mixin/server/MinecraftDedicatedServerMixin.java | 10 +++------- bootstrap/fabric/src/main/resources/fabric.mod.json | 2 +- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 112760009..e120ba1b2 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.10-SNAPSHOT' + id 'fabric-loom' version '0.12-SNAPSHOT' id 'maven-publish' id 'com.github.johnrengelman.shadow' version '7.0.0' id 'java' @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation 'org.geysermc:core:2.0.3-SNAPSHOT' - shadow('org.geysermc:core:2.0.3-SNAPSHOT') { + implementation "org.geysermc:core:${project.mod_version}" + shadow("org.geysermc:core:${project.mod_version}") { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' @@ -93,7 +93,7 @@ jar { remapJar { dependsOn(shadowJar) - input.set shadowJar.archiveFile.get() + input = tasks.shadowJar.archiveFile } // configure the maven publication diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 1d9b12e67..8e6528e25 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -1,14 +1,14 @@ # Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G +org.gradle.jvmargs=-Xmx2G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.18.2 -yarn_mappings=1.18.2+build.1 -loader_version=0.12.8 +minecraft_version=1.19 +yarn_mappings=1.19+build.1 +loader_version=0.14.6 # Mod Properties -mod_version=2.0.3-SNAPSHOT +mod_version=2.0.4-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.43.1+1.18 +fabric_version=0.55.2+1.19 \ No newline at end of file diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index 1fa9f55ae..57f877637 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -27,7 +27,7 @@ package org.geysermc.platform.fabric.command; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.text.ChatColor; @@ -49,7 +49,7 @@ public class FabricCommandSender implements CommandSender { @Override public void sendMessage(String message) { if (source.getEntity() instanceof ServerPlayerEntity) { - ((ServerPlayerEntity) source.getEntity()).sendMessage(new LiteralText(message), false); + ((ServerPlayerEntity) source.getEntity()).sendMessage(Text.literal(message), false); } else { GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java index 1fc945f28..6a6d3e0e6 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -30,7 +30,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.world.GameMode; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.platform.fabric.GeyserFabricMod; @@ -58,7 +58,7 @@ public class IntegratedServerMixin implements GeyserServerPortGetter { // Ensure player locale has been loaded, in case it's different from Java system language GeyserLocale.loadGeyserLocale(this.client.options.language); // Give indication that Geyser is loaded - this.client.player.sendMessage(new LiteralText(GeyserLocale.getPlayerLocaleString("geyser.core.start", + this.client.player.sendMessage(Text.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start", this.client.options.language, "localhost", String.valueOf(this.lanPort))), false); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java index e30181f00..a41a08342 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -25,27 +25,23 @@ package org.geysermc.platform.fabric.mixin.server; -import com.mojang.authlib.GameProfileRepository; -import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.datafixers.DataFixer; import net.minecraft.resource.ResourcePackManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.SaveLoader; import net.minecraft.server.WorldGenerationProgressListenerFactory; import net.minecraft.server.dedicated.MinecraftDedicatedServer; -import net.minecraft.util.UserCache; +import net.minecraft.util.ApiServices; import net.minecraft.world.level.storage.LevelStorage; import org.geysermc.platform.fabric.GeyserServerPortGetter; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import java.net.Proxy; @Mixin(MinecraftDedicatedServer.class) public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter { - // Constructor to compile - public MinecraftDedicatedServerMixin(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, @Nullable MinecraftSessionService sessionService, @Nullable GameProfileRepository gameProfileRepo, @Nullable UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { - super(serverThread, session, dataPackManager, saveLoader, proxy, dataFixer, sessionService, gameProfileRepo, userCache, worldGenerationProgressListenerFactory); + public MinecraftDedicatedServerMixin(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, ApiServices apiServices, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) { + super(serverThread, session, dataPackManager, saveLoader, proxy, dataFixer, apiServices, worldGenerationProgressListenerFactory); } @Override diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 54478f150..fd04f8ecf 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.11.3", "fabric": "*", - "minecraft": ">=1.18.2" + "minecraft": ">=1.19" } } From fb03885eb8564d3c82c4875cfab87e6612939644 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 14 Jun 2022 21:33:50 -0400 Subject: [PATCH 091/100] Consistent file name; remove Netty IO_Uring --- bootstrap/fabric/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index e120ba1b2..f25af4ee8 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -32,6 +32,8 @@ dependencies { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' + exclude group: 'it.unimi.dsi.fastutil' + exclude group: 'io.netty.incubator' } } @@ -80,7 +82,6 @@ task sourcesJar(type: Jar, dependsOn: classes) { shadowJar { configurations = [project.configurations.shadow] - relocate("it.unimi.dsi.fastutil", "org.geysermc.relocate.fastutil") relocate("org.objectweb.asm", "org.geysermc.relocate.asm") relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson") @@ -94,6 +95,7 @@ jar { remapJar { dependsOn(shadowJar) input = tasks.shadowJar.archiveFile + archiveName = "Geyser-Fabric.jar" } // configure the maven publication From 3b32b16bc8ea1fa436dd1e891da54fbd45c6b974 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 14 Jun 2022 21:49:47 -0400 Subject: [PATCH 092/100] Properly exclude Fastutil --- bootstrap/fabric/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index f25af4ee8..96f3ee8b1 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -32,7 +32,7 @@ dependencies { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' - exclude group: 'it.unimi.dsi.fastutil' + exclude group: 'com.nukkitx.fastutil' exclude group: 'io.netty.incubator' } } From 2f1fa6d4177d44d462400df3f9c65d5451d78ac7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 14 Jul 2022 16:52:58 -0400 Subject: [PATCH 093/100] Update to 2.0.5-SNAPSHOT --- bootstrap/fabric/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 8e6528e25..7817ad24f 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,9 +6,9 @@ minecraft_version=1.19 yarn_mappings=1.19+build.1 loader_version=0.14.6 # Mod Properties -mod_version=2.0.4-SNAPSHOT +mod_version=2.0.5-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.55.2+1.19 \ No newline at end of file +fabric_version=0.55.2+1.19 From bd34d65580a898c52a723b5bde6a7addb33be0a1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 14 Jul 2022 17:01:09 -0400 Subject: [PATCH 094/100] Update README.md --- bootstrap/fabric/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/README.md b/bootstrap/fabric/README.md index ef83f6db7..883d03289 100644 --- a/bootstrap/fabric/README.md +++ b/bootstrap/fabric/README.md @@ -2,7 +2,7 @@ [![forthebadge made-with-java](https://forthebadge.com/images/badges/made-with-java.svg)](https://java.com/) -Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/java-1.18/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/java-1.18/) +Download: [![Build Status](https://ci.nukkitx.com/job/GeyserMC/job/Geyser-Fabric/job/master/badge/icon)](https://ci.opencollab.dev//job/GeyserMC/job/Geyser-Fabric/job/master/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) From 8b300426dc9d8cb7b77a8ea55e67af236d0cc5a2 Mon Sep 17 00:00:00 2001 From: Carlos Ramos <57056947+CarlosRamosDev@users.noreply.github.com> Date: Thu, 28 Jul 2022 17:56:13 -0600 Subject: [PATCH 095/100] Update for Java 1.19.1 and Geyser 2.0.6-SNAPSHOT (#62) * Updated to Minecraft 1.19.1 * Update fabric.mod.json --- bootstrap/fabric/gradle.properties | 10 +++++----- bootstrap/fabric/src/main/resources/fabric.mod.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 7817ad24f..c42b9c713 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx2G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.19 -yarn_mappings=1.19+build.1 -loader_version=0.14.6 +minecraft_version=1.19.1 +yarn_mappings=1.19.1+build.1 +loader_version=0.14.8 # Mod Properties -mod_version=2.0.5-SNAPSHOT +mod_version=2.0.6-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.55.2+1.19 +fabric_version=0.58.5+1.19.1 diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index fd04f8ecf..c02f07c3f 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -23,8 +23,8 @@ "geyser-fabric.mixins.json" ], "depends": { - "fabricloader": ">=0.11.3", + "fabricloader": ">=0.14.8", "fabric": "*", - "minecraft": ">=1.19" + "minecraft": ">=1.19.1" } } From e960303352f8a5a575ba002e1b1427e7b02e2542 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 13 Aug 2022 20:27:13 -0400 Subject: [PATCH 096/100] Update Geyser version --- bootstrap/fabric/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index c42b9c713..9c79b7141 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.19.1 yarn_mappings=1.19.1+build.1 loader_version=0.14.8 # Mod Properties -mod_version=2.0.6-SNAPSHOT +mod_version=2.0.7-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies From 62bd2cc543c4b9819b46151a43ac7d6e5df874c0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 18 Aug 2022 19:33:08 -0400 Subject: [PATCH 097/100] Allow any 1.19 version --- bootstrap/fabric/src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index c02f07c3f..9d66ca08c 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,6 @@ "depends": { "fabricloader": ">=0.14.8", "fabric": "*", - "minecraft": ">=1.19.1" + "minecraft": ">=1.19" } } From c97ff4f6124c7d36e19569b9b84db72d6f1ddf3b Mon Sep 17 00:00:00 2001 From: AnhNguyenlost13 <94160753+AnhNguyenlost13@users.noreply.github.com> Date: Wed, 7 Sep 2022 20:58:34 +0700 Subject: [PATCH 098/100] Add tooltips command (#65) Tooltips command should be there and enabled by default --- bootstrap/fabric/src/main/resources/permissions.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/fabric/src/main/resources/permissions.yml b/bootstrap/fabric/src/main/resources/permissions.yml index 8a995f8dc..ae20447ed 100644 --- a/bootstrap/fabric/src/main/resources/permissions.yml +++ b/bootstrap/fabric/src/main/resources/permissions.yml @@ -6,7 +6,8 @@ commands: - statistics - settings - offhand + - tooltips # - list # - reload # - version -# - dump \ No newline at end of file +# - dump From b794569388a717cd8b746a965da1edfd9fd63554 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 22 Sep 2022 19:49:35 -0400 Subject: [PATCH 099/100] 1.19.30 support probably --- bootstrap/fabric/build.gradle | 4 ++-- bootstrap/fabric/gradle.properties | 2 +- .../platform/fabric/GeyserFabricMod.java | 22 ++++++++++--------- .../fabric/command/FabricCommandSender.java | 6 ++--- .../command/GeyserFabricCommandExecutor.java | 12 +++++----- .../command/GeyserFabricCommandManager.java | 6 ++--- .../world/GeyserFabricWorldManager.java | 3 +-- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle index 96f3ee8b1..2ea9fd686 100644 --- a/bootstrap/fabric/build.gradle +++ b/bootstrap/fabric/build.gradle @@ -27,8 +27,8 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - implementation "org.geysermc:core:${project.mod_version}" - shadow("org.geysermc:core:${project.mod_version}") { + api "org.geysermc.geyser:core:${project.mod_version}" + shadow("org.geysermc.geyser:core:${project.mod_version}") { exclude group: 'com.google.guava', module: "guava" exclude group: 'com.google.code.gson', module: "gson" exclude group: 'org.slf4j' diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties index 9c79b7141..341d6bbe4 100644 --- a/bootstrap/fabric/gradle.properties +++ b/bootstrap/fabric/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.19.1 yarn_mappings=1.19.1+build.1 loader_version=0.14.8 # Mod Properties -mod_version=2.0.7-SNAPSHOT +mod_version=2.1.0-SNAPSHOT maven_group=org.geysermc.platform archives_base_name=Geyser-Fabric # Dependencies diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index f6a657bba..5a0b2527a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -37,11 +37,12 @@ import org.apache.logging.log4j.LogManager; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; -import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -142,7 +143,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { public void startGeyser(MinecraftServer server) { this.server = server; - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { + if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); String ip = server.getServerIp(); int port = ((GeyserServerPortGetter) server).geyser$getServerPort(); @@ -153,12 +154,12 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { } if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port()); } Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate"); boolean floodgatePresent = floodgate.isPresent(); - if (geyserConfig.getRemote().getAuthType() == AuthType.FLOODGATE && !floodgatePresent) { + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); return; } else if (geyserConfig.isAutoconfiguredRemote() && floodgatePresent) { @@ -169,7 +170,8 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { geyserConfig.loadFloodgate(this, floodgate.orElse(null)); - this.connector = GeyserImpl.start(PlatformType.FABRIC, this); + this.connector = GeyserImpl.load(PlatformType.FABRIC, this); + GeyserImpl.start(); // shrug this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); @@ -180,13 +182,13 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { // Start command building // Set just "geyser" as the help command GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(connector, - connector.getCommandManager().getCommands().get("help"), !playerCommands.contains("help")); + (GeyserCommand) connector.commandManager().getCommands().get("help"), !playerCommands.contains("help")); commandExecutors.add(helpExecutor); LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser").executes(helpExecutor); // Register all subcommands as valid - for (Map.Entry command : connector.getCommandManager().getCommands().entrySet()) { - GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(connector, command.getValue(), + for (Map.Entry command : connector.commandManager().getCommands().entrySet()) { + GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(connector, (GeyserCommand) command.getValue(), !playerCommands.contains(command.getKey())); commandExecutors.add(executor); builder.then(net.minecraft.server.command.CommandManager.literal(command.getKey()).executes(executor)); @@ -216,7 +218,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { } @Override - public CommandManager getGeyserCommandManager() { + public GeyserCommandManager getGeyserCommandManager() { return geyserCommandManager; } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java index 57f877637..20dee1b21 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java @@ -29,11 +29,11 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.ChatColor; import org.geysermc.platform.fabric.GeyserFabricMod; -public class FabricCommandSender implements CommandSender { +public class FabricCommandSender implements GeyserCommandSource { private final ServerCommandSource source; @@ -66,7 +66,7 @@ public class FabricCommandSender implements CommandSender { // Workaround for our commands because fabric doesn't have native permissions for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { - if (executor.getCommand().getPermission().equals(s)) { + if (executor.getCommand().permission().equals(s)) { return executor.canRun(source); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java index c1d8ebc29..07b8bd519 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -29,15 +29,17 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import net.minecraft.server.command.ServerCommandSource; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandExecutor; import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.platform.fabric.GeyserFabricMod; import org.geysermc.platform.fabric.GeyserFabricPermissions; -public class GeyserFabricCommandExecutor extends CommandExecutor implements Command { +import java.util.Collections; + +public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command { private final GeyserCommand command; /** @@ -46,7 +48,7 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm private final boolean requiresPermission; public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command, boolean requiresPermission) { - super(connector); + super(connector, Collections.singletonMap(command.name(), command)); this.command = command; this.requiresPermission = requiresPermission; } @@ -70,12 +72,12 @@ public class GeyserFabricCommandExecutor extends CommandExecutor implements Comm sender.sendMessage(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); return 0; } - if (this.command.getName().equals("reload")) { + if (this.command.name().equals("reload")) { GeyserFabricMod.getInstance().setReloading(true); } if (command.isBedrockOnly() && session == null) { - sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.getLocale())); + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale())); return 0; } command.execute(session, sender, new String[0]); diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java index d548aa823..feaf40130 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java @@ -26,16 +26,16 @@ package org.geysermc.platform.fabric.command; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommandManager; -public class GeyserFabricCommandManager extends CommandManager { +public class GeyserFabricCommandManager extends GeyserCommandManager { public GeyserFabricCommandManager(GeyserImpl connector) { super(connector); } @Override - public String getDescription(String command) { + public String description(String command) { return ""; } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java index 5a66f6ae8..40c7fd302 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java @@ -124,10 +124,9 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { @Override public boolean hasPermission(GeyserSession session, String permission) { - // Workaround for our commands because fabric doesn't have native permissions for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { - if (executor.getCommand().getPermission().equals(permission)) { + if (executor.getCommand().permission().equals(permission)) { return executor.canRun(getPlayer(session).getCommandSource()); } } From 91ad2e58fc15233f015037acfec7d5a5f2ed4f2b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 22 Sep 2022 21:25:46 -0400 Subject: [PATCH 100/100] Should fix the command NPE --- .../main/java/org/geysermc/platform/fabric/GeyserFabricMod.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java index 5a0b2527a..cdd7d358a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java @@ -176,6 +176,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); this.geyserCommandManager = new GeyserFabricCommandManager(connector); + this.geyserCommandManager.init(); this.geyserWorldManager = new GeyserFabricWorldManager(server);