From 754c2f3d783ad74082cfd7942492d7e33d7b170f Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 6 Oct 2020 12:15:07 -0400 Subject: [PATCH 001/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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 zcma&ObC74zk}X`WF59+k+qTVL*+!RbS9RI8Z5v&-ZFK4Nn|tqzcjwK__x+Iv5xL`> zj94dg?X`0sMHx^qXds{;KY)OMg#H>35XgTVfq6#vc9ww|9) z@UMfwUqk)B9p!}NrNqTlRO#i!ALOPcWo78-=iy}NsAr~T8T0X0%G{DhX~u-yEwc29WQ4D zuv2j{a&j?qB4wgCu`zOXj!~YpTNFg)TWoV>DhYlR^Gp^rkOEluvxkGLB?!{fD!T@( z%3cy>OkhbIKz*R%uoKqrg1%A?)uTZD&~ssOCUBlvZhx7XHQ4b7@`&sPdT475?*zWy z>xq*iK=5G&N6!HiZaD{NSNhWL;+>Quw_#ZqZbyglna!Fqn3N!$L`=;TFPrhodD-Q` z1l*=DP2gKJP@)cwI@-M}?M$$$%u~=vkeC%>cwR$~?y6cXx-M{=wdT4|3X(@)a|KkZ z`w$6CNS@5gWS7s7P86L<=vg$Mxv$?)vMj3`o*7W4U~*Nden}wz=y+QtuMmZ{(Ir1D zGp)ZsNiy{mS}Au5;(fYf93rs^xvi(H;|H8ECYdC`CiC&G`zw?@)#DjMc7j~daL_A$ z7e3nF2$TKlTi=mOftyFBt8*Xju-OY@2k@f3YBM)-v8+5_o}M?7pxlNn)C0Mcd@87?+AA4{Ti2ptnYYKGp`^FhcJLlT%RwP4k$ad!ho}-^vW;s{6hnjD0*c39k zrm@PkI8_p}mnT&5I@=O1^m?g}PN^8O8rB`;t`6H+?Su0IR?;8txBqwK1Au8O3BZAX zNdJB{bpQWR@J|e=Z>XSXV1DB{uhr3pGf_tb)(cAkp)fS7*Qv))&Vkbb+cvG!j}ukd zxt*C8&RN}5ck{jkw0=Q7ldUp0FQ&Pb_$M7a@^nf`8F%$ftu^jEz36d#^M8Ia{VaTy z5(h$I)*l3i!VpPMW+XGgzL~fcN?{~1QWu9!Gu0jOWWE zNW%&&by0DbXL&^)r-A*7R@;T$P}@3eOj#gqJ!uvTqBL5bupU91UK#d|IdxBUZAeh1 z>rAI#*Y4jv>uhOh7`S@mnsl0g@1C;k$Z%!d*n8#_$)l}-1&z2kr@M+xWoKR z!KySy-7h&Bf}02%JeXmQGjO3ntu={K$jy$rFwfSV8!zqAL_*&e2|CJ06`4&0+ceI026REfNT>JzAdwmIlKLEr2? zaZ#d*XFUN*gpzOxq)cysr&#6zNdDDPH% zd8_>3B}uA7;bP4fKVdd~Og@}dW#74ceETOE- zlZgQqQfEc?-5ly(Z5`L_CCM!&Uxk5#wgo=OLs-kFHFG*cTZ)$VE?c_gQUW&*!2@W2 z7Lq&_Kf88OCo?BHCtwe*&fu&8PQ(R5&lnYo8%+U73U)Ec2&|A)Y~m7(^bh299REPe zn#gyaJ4%o4>diN3z%P5&_aFUmlKytY$t21WGwx;3?UC}vlxi-vdEQgsKQ;=#sJ#ll zZeytjOad$kyON4XxC}frS|Ybh`Yq!<(IrlOXP3*q86ImyV*mJyBn$m~?#xp;EplcM z+6sez%+K}Xj3$YN6{}VL;BZ7Fi|iJj-ywlR+AP8lq~mnt5p_%VmN{Sq$L^z!otu_u znVCl@FgcVXo510e@5(wnko%Pv+^r^)GRh;>#Z(|#cLnu_Y$#_xG&nvuT+~gzJsoSi zBvX`|IS~xaold!`P!h(v|=>!5gk)Q+!0R1Ge7!WpRP{*Ajz$oGG$_?Ajvz6F0X?809o`L8prsJ*+LjlGfSziO;+ zv>fyRBVx#oC0jGK8$%$>Z;0+dfn8x;kHFQ?Rpi7(Rc{Uq{63Kgs{IwLV>pDK7yX-2 zls;?`h!I9YQVVbAj7Ok1%Y+F?CJa-Jl>1x#UVL(lpzBBH4(6v0^4 z3Tf`INjml5`F_kZc5M#^J|f%7Hgxg3#o}Zwx%4l9yYG!WaYUA>+dqpRE3nw#YXIX%= ziH3iYO~jr0nP5xp*VIa#-aa;H&%>{mfAPPlh5Fc!N7^{!z$;p-p38aW{gGx z)dFS62;V;%%fKp&i@+5x=Cn7Q>H`NofJGXmNeh{sOL+Nk>bQJJBw3K*H_$}%*xJM=Kh;s#$@RBR z|75|g85da@#qT=pD777m$wI!Q8SC4Yw3(PVU53bzzGq$IdGQoFb-c_(iA_~qD|eAy z@J+2!tc{|!8fF;%6rY9`Q!Kr>MFwEH%TY0y>Q(D}xGVJM{J{aGN0drG&|1xO!Ttdw z-1^gQ&y~KS5SeslMmoA$Wv$ly={f}f9<{Gm!8ycp*D9m*5Ef{ymIq!MU01*)#J1_! zM_i4{LYButqlQ>Q#o{~W!E_#(S=hR}kIrea_67Z5{W>8PD>g$f;dTvlD=X@T$8D0;BWkle@{VTd&D5^)U>(>g(jFt4lRV6A2(Te->ooI{nk-bZ(gwgh zaH4GT^wXPBq^Gcu%xW#S#p_&x)pNla5%S5;*OG_T^PhIIw1gXP&u5c;{^S(AC*+$> z)GuVq(FT@zq9;i{*9lEsNJZ)??BbSc5vF+Kdh-kL@`(`l5tB4P!9Okin2!-T?}(w% zEpbEU67|lU#@>DppToestmu8Ce=gz=e#V+o)v)#e=N`{$MI5P0O)_fHt1@aIC_QCv=FO`Qf=Ga%^_NhqGI)xtN*^1n{ z&vgl|TrKZ3Vam@wE0p{c3xCCAl+RqFEse@r*a<3}wmJl-hoJoN<|O2zcvMRl<#BtZ z#}-bPCv&OTw`GMp&n4tutf|er`@#d~7X+);##YFSJ)BitGALu}-N*DJdCzs(cQ?I- z6u(WAKH^NUCcOtpt5QTsQRJ$}jN28ZsYx+4CrJUQ%egH zo#tMoywhR*oeIkS%}%WUAIbM`D)R6Ya&@sZvvUEM7`fR0Ga03*=qaEGq4G7-+30Ck zRkje{6A{`ebq?2BTFFYnMM$xcQbz0nEGe!s%}O)m={`075R0N9KTZ>vbv2^eml>@}722%!r#6Wto}?vNst? zs`IasBtcROZG9+%rYaZe^=5y3chDzBf>;|5sP0!sP(t^= z^~go8msT@|rp8LJ8km?4l?Hb%o10h7(ixqV65~5Y>n_zG3AMqM3UxUNj6K-FUgMT7 z*Dy2Y8Ws+%`Z*~m9P zCWQ8L^kA2$rf-S@qHow$J86t)hoU#XZ2YK~9GXVR|*`f6`0&8j|ss_Ai-x=_;Df^*&=bW$1nc{Gplm zF}VF`w)`5A;W@KM`@<9Bw_7~?_@b{Z`n_A6c1AG#h#>Z$K>gX6reEZ*bZRjCup|0# zQ{XAb`n^}2cIwLTN%5Ix`PB*H^(|5S{j?BwItu+MS`1)VW=TnUtt6{3J!WR`4b`LW z?AD#ZmoyYpL=903q3LSM=&5eNP^dwTDRD~iP=}FXgZ@2WqfdyPYl$9do?wX{RU*$S zgQ{OqXK-Yuf4+}x6P#A*la&^G2c2TC;aNNZEYuB(f25|5eYi|rd$;i0qk7^3Ri8of ziP~PVT_|4$n!~F-B1_Et<0OJZ*e+MN;5FFH`iec(lHR+O%O%_RQhvbk-NBQ+$)w{D+dlA0jxI;z|P zEKW`!X)${xzi}Ww5G&@g0akBb_F`ziv$u^hs0W&FXuz=Ap>SUMw9=M?X$`lgPRq11 zqq+n44qL;pgGO+*DEc+Euv*j(#%;>p)yqdl`dT+Og zZH?FXXt`<0XL2@PWYp|7DWzFqxLK)yDXae&3P*#+f+E{I&h=$UPj;ey9b`H?qe*Oj zV|-qgI~v%&oh7rzICXfZmg$8$B|zkjliQ=e4jFgYCLR%yi!9gc7>N z&5G#KG&Hr+UEfB;M(M>$Eh}P$)<_IqC_WKOhO4(cY@Gn4XF(#aENkp&D{sMQgrhDT zXClOHrr9|POHqlmm+*L6CK=OENXbZ+kb}t>oRHE2xVW<;VKR@ykYq04LM9L-b;eo& zl!QQo!Sw{_$-qosixZJWhciN>Gbe8|vEVV2l)`#5vKyrXc6E`zmH(76nGRdL)pqLb@j<&&b!qJRLf>d`rdz}^ZSm7E;+XUJ ziy;xY&>LM?MA^v0Fu8{7hvh_ynOls6CI;kQkS2g^OZr70A}PU;i^~b_hUYN1*j-DD zn$lHQG9(lh&sDii)ip*{;Sb_-Anluh`=l~qhqbI+;=ZzpFrRp&T+UICO!OoqX@Xr_ z32iJ`xSpx=lDDB_IG}k+GTYG@K8{rhTS)aoN8D~Xfe?ul&;jv^E;w$nhu-ICs&Q)% zZ=~kPNZP0-A$pB8)!`TEqE`tY3Mx^`%O`?EDiWsZpoP`e-iQ#E>fIyUx8XN0L z@S-NQwc;0HjSZKWDL}Au_Zkbh!juuB&mGL0=nO5)tUd_4scpPy&O7SNS^aRxUy0^< zX}j*jPrLP4Pa0|PL+nrbd4G;YCxCK-=G7TG?dby~``AIHwxqFu^OJhyIUJkO0O<>_ zcpvg5Fk$Wpj}YE3;GxRK67P_Z@1V#+pu>pRj0!mFf(m_WR3w3*oQy$s39~U7Cb}p(N&8SEwt+)@%o-kW9Ck=^?tvC2$b9% ze9(Jn+H`;uAJE|;$Flha?!*lJ0@lKfZM>B|c)3lIAHb;5OEOT(2453m!LgH2AX=jK zQ93An1-#l@I@mwB#pLc;M7=u6V5IgLl>E%gvE|}Hvd4-bE1>gs(P^C}gTv*&t>W#+ zASLRX$y^DD3Jrht zwyt`yuA1j(TcP*0p*Xkv>gh+YTLrcN_HuaRMso~0AJg`^nL#52dGBzY+_7i)Ud#X) zVwg;6$WV20U2uyKt8<)jN#^1>PLg`I`@Mmut*Zy!c!zshSA!e^tWVoKJD%jN&ml#{ z@}B$j=U5J_#rc%T7(DGKF+WwIblEZ;Vq;CsG~OKxhWYGJx#g7fxb-_ya*D0=_Ys#f zhXktl=Vnw#Z_neW>Xe#EXT(4sT^3p6srKby4Ma5LLfh6XrHGFGgM;5Z}jv-T!f~=jT&n>Rk z4U0RT-#2fsYCQhwtW&wNp6T(im4dq>363H^ivz#>Sj;TEKY<)dOQU=g=XsLZhnR>e zd}@p1B;hMsL~QH2Wq>9Zb; zK`0`09fzuYg9MLJe~cdMS6oxoAD{kW3sFAqDxvFM#{GpP^NU@9$d5;w^WgLYknCTN z0)N425mjsJTI@#2kG-kB!({*+S(WZ-{SckG5^OiyP%(6DpRsx60$H8M$V65a_>oME z^T~>oG7r!ew>Y)&^MOBrgc-3PezgTZ2xIhXv%ExMFgSf5dQbD=Kj*!J4k^Xx!Z>AW ziZfvqJvtm|EXYsD%A|;>m1Md}j5f2>kt*gngL=enh<>#5iud0dS1P%u2o+>VQ{U%(nQ_WTySY(s#~~> zrTsvp{lTSup_7*Xq@qgjY@1#bisPCRMMHnOL48qi*jQ0xg~TSW%KMG9zN1(tjXix()2$N}}K$AJ@GUth+AyIhH6Aeh7qDgt#t*`iF5#A&g4+ zWr0$h9Zx6&Uo2!Ztcok($F>4NA<`dS&Js%L+67FT@WmI)z#fF~S75TUut%V($oUHw z$IJsL0X$KfGPZYjB9jaj-LaoDD$OMY4QxuQ&vOGo?-*9@O!Nj>QBSA6n$Lx|^ zky)4+sy{#6)FRqRt6nM9j2Lzba!U;aL%ZcG&ki1=3gFx6(&A3J-oo|S2_`*w9zT)W z4MBOVCp}?4nY)1))SOX#6Zu0fQQ7V{RJq{H)S#;sElY)S)lXTVyUXTepu4N)n85Xo zIpWPT&rgnw$D2Fsut#Xf-hO&6uA0n~a;a3!=_!Tq^TdGE&<*c?1b|PovU}3tfiIUu z){4W|@PY}zJOXkGviCw^x27%K_Fm9GuKVpd{P2>NJlnk^I|h2XW0IO~LTMj>2<;S* zZh2uRNSdJM$U$@=`zz}%;ucRx{aKVxxF7?0hdKh6&GxO6f`l2kFncS3xu0Ly{ew0& zeEP*#lk-8-B$LD(5yj>YFJ{yf5zb41PlW7S{D9zC4Aa4nVdkDNH{UsFJp)q-`9OYt zbOKkigbmm5hF?tttn;S4g^142AF^`kiLUC?e7=*JH%Qe>uW=dB24NQa`;lm5yL>Dyh@HbHy-f%6Vz^ zh&MgwYsh(z#_fhhqY$3*f>Ha}*^cU-r4uTHaT?)~LUj5``FcS46oyoI5F3ZRizVD% zPFY(_S&5GN8$Nl2=+YO6j4d|M6O7CmUyS&}m4LSn6}J`$M0ZzT&Ome)ZbJDFvM&}A zZdhDn(*viM-JHf84$!I(8eakl#zRjJH4qfw8=60 z11Ely^FyXjVvtv48-Fae7p=adlt9_F^j5#ZDf7)n!#j?{W?@j$Pi=k`>Ii>XxrJ?$ z^bhh|X6qC8d{NS4rX5P!%jXy=>(P+r9?W(2)|(=a^s^l~x*^$Enw$~u%WRuRHHFan{X|S;FD(Mr z@r@h^@Bs#C3G;~IJMrERd+D!o?HmFX&#i|~q(7QR3f8QDip?ms6|GV_$86aDb|5pc?_-jo6vmWqYi{P#?{m_AesA4xX zi&ki&lh0yvf*Yw~@jt|r-=zpj!bw<6zI3Aa^Wq{|*WEC}I=O!Re!l~&8|Vu<$yZ1p zs-SlwJD8K!$(WWyhZ+sOqa8cciwvyh%zd`r$u;;fsHn!hub0VU)bUv^QH?x30#;tH zTc_VbZj|prj7)d%ORU;Vs{#ERb>K8>GOLSImnF7JhR|g$7FQTU{(a7RHQ*ii-{U3X z^7+vM0R$8b3k1aSU&kxvVPfOz3~)0O2iTYinV9_5{pF18j4b{o`=@AZIOAwwedB2@ ztXI1F04mg{<>a-gdFoRjq$6#FaevDn$^06L)k%wYq03&ysdXE+LL1#w$rRS1Y;BoS zH1x}{ms>LHWmdtP(ydD!aRdAa(d@csEo z0EF9L>%tppp`CZ2)jVb8AuoYyu;d^wfje6^n6`A?6$&%$p>HcE_De-Zh)%3o5)LDa zskQ}%o7?bg$xUj|n8gN9YB)z!N&-K&!_hVQ?#SFj+MpQA4@4oq!UQ$Vm3B`W_Pq3J z=ngFP4h_y=`Iar<`EESF9){%YZVyJqLPGq07TP7&fSDmnYs2NZQKiR%>){imTBJth zPHr@p>8b+N@~%43rSeNuOz;rgEm?14hNtI|KC6Xz1d?|2J`QS#`OW7gTF_;TPPxu@ z)9J9>3Lx*bc>Ielg|F3cou$O0+<b34_*ZJhpS&$8DP>s%47a)4ZLw`|>s=P_J4u z?I_%AvR_z8of@UYWJV?~c4Yb|A!9n!LEUE6{sn@9+D=0w_-`szJ_T++x3MN$v-)0d zy`?1QG}C^KiNlnJBRZBLr4G~15V3$QqC%1G5b#CEB0VTr#z?Ug%Jyv@a`QqAYUV~^ zw)d|%0g&kl{j#FMdf$cn(~L@8s~6eQ)6{`ik(RI(o9s0g30Li{4YoxcVoYd+LpeLz zai?~r)UcbYr@lv*Z>E%BsvTNd`Sc?}*}>mzJ|cr0Y(6rA7H_6&t>F{{mJ^xovc2a@ zFGGDUcGgI-z6H#o@Gj29C=Uy{wv zQHY2`HZu8+sBQK*_~I-_>fOTKEAQ8_Q~YE$c?cSCxI;vs-JGO`RS464Ft06rpjn+a zqRS0Y3oN(9HCP@{J4mOWqIyD8PirA!pgU^Ne{LHBG;S*bZpx3|JyQDGO&(;Im8!ed zNdpE&?3U?E@O~>`@B;oY>#?gXEDl3pE@J30R1;?QNNxZ?YePc)3=NS>!STCrXu*lM z69WkLB_RBwb1^-zEm*tkcHz3H;?v z;q+x0Jg$|?5;e1-kbJnuT+^$bWnYc~1qnyVTKh*cvM+8yJT-HBs1X@cD;L$su65;i z2c1MxyL~NuZ9+)hF=^-#;dS#lFy^Idcb>AEDXu1!G4Kd8YPy~0lZz$2gbv?su}Zn} zGtIbeYz3X8OA9{sT(aleold_?UEV{hWRl(@)NH6GFH@$<8hUt=dNte%e#Jc>7u9xi zuqv!CRE@!fmZZ}3&@$D>p0z=*dfQ_=IE4bG0hLmT@OP>x$e`qaqf_=#baJ8XPtOpWi%$ep1Y)o2(sR=v)M zt(z*pGS$Z#j_xq_lnCr+x9fwiT?h{NEn#iK(o)G&Xw-#DK?=Ms6T;%&EE${Gq_%99 z6(;P~jPKq9llc+cmI(MKQ6*7PcL)BmoI}MYFO)b3-{j>9FhNdXLR<^mnMP`I7z0v` zj3wxcXAqi4Z0kpeSf>?V_+D}NULgU$DBvZ^=0G8Bypd7P2>;u`yW9`%4~&tzNJpgp zqB+iLIM~IkB;ts!)exn643mAJ8-WlgFE%Rpq!UMYtB?$5QAMm)%PT0$$2{>Yu7&U@ zh}gD^Qdgu){y3ANdB5{75P;lRxSJPSpQPMJOiwmpMdT|?=q;&$aTt|dl~kvS z+*i;6cEQJ1V`R4Fd>-Uzsc=DPQ7A7#VPCIf!R!KK%LM&G%MoZ0{-8&99H!|UW$Ejv zhDLX3ESS6CgWTm#1ZeS2HJb`=UM^gsQ84dQpX(ESWSkjn>O zVxg%`@mh(X9&&wN$lDIc*@>rf?C0AD_mge3f2KkT6kGySOhXqZjtA?5z`vKl_{(5g z&%Y~9p?_DL{+q@siT~*3Q*$nWXQfNN;%s_eHP_A;O`N`SaoB z6xYR;z_;HQ2xAa9xKgx~2f2xEKiEDpGPH1d@||v#f#_Ty6_gY>^oZ#xac?pc-F`@ z*}8sPV@xiz?efDMcmmezYVw~qw=vT;G1xh+xRVBkmN66!u(mRG3G6P#v|;w@anEh7 zCf94arw%YB*=&3=RTqX?z4mID$W*^+&d6qI*LA-yGme;F9+wTsNXNaX~zl2+qIK&D-aeN4lr0+yP;W>|Dh?ms_ogT{DT+ ztXFy*R7j4IX;w@@R9Oct5k2M%&j=c_rWvoul+` z<18FH5D@i$P38W9VU2(EnEvlJ(SHCqTNBa)brkIjGP|jCnK&Qi%97tikU}Y#3L?s! z2ujL%YiHO-#!|g5066V01hgT#>fzls7P>+%D~ogOT&!Whb4iF=CnCto82Yb#b`YoVsj zS2q^W0Rj!RrM@=_GuPQy5*_X@Zmu`TKSbqEOP@;Ga&Rrr>#H@L41@ZX)LAkbo{G8+ z;!5EH6vv-ip0`tLB)xUuOX(*YEDSWf?PIxXe`+_B8=KH#HFCfthu}QJylPMTNmoV; zC63g%?57(&osaH^sxCyI-+gwVB|Xs2TOf=mgUAq?V~N_5!4A=b{AXbDae+yABuuu3B_XSa4~c z1s-OW>!cIkjwJf4ZhvT|*IKaRTU)WAK=G|H#B5#NB9<{*kt?7`+G*-^<)7$Iup@Um z7u*ABkG3F*Foj)W9-I&@BrN8(#$7Hdi`BU#SR1Uz4rh&=Ey!b76Qo?RqBJ!U+rh(1 znw@xw5$)4D8OWtB_^pJO*d~2Mb-f~>I!U#*=Eh*xa6$LX?4Evp4%;ENQR!mF4`f7F zpG!NX=qnCwE8@NAbQV`*?!v0;NJ(| zBip8}VgFVsXFqslXUV>_Z>1gmD(7p#=WACXaB|Y`=Kxa=p@_ALsL&yAJ`*QW^`2@% zW7~Yp(Q@ihmkf{vMF?kqkY%SwG^t&CtfRWZ{syK@W$#DzegcQ1>~r7foTw3^V1)f2Tq_5f$igmfch;8 zT-<)?RKcCdQh6x^mMEOS;4IpQ@F2q-4IC4%*dU@jfHR4UdG>Usw4;7ESpORL|2^#jd+@zxz{(|RV*1WKrw-)ln*8LnxVkKDfGDHA%7`HaiuvhMu%*mY9*Ya{Ti#{DW?i0 zXXsp+Bb(_~wv(3t70QU3a$*<$1&zm1t++x#wDLCRI4K)kU?Vm9n2c0m@TyUV&&l9%}fulj!Z9)&@yIcQ3gX}l0b1LbIh4S z5C*IDrYxR%qm4LVzSk{0;*npO_SocYWbkAjA6(^IAwUnoAzw_Uo}xYFo?Y<-4Zqec z&k7HtVlFGyt_pA&kX%P8PaRD8y!Wsnv}NMLNLy-CHZf(ObmzV|t-iC#@Z9*d-zUsx zxcYWw{H)nYXVdnJu5o-U+fn~W z-$h1ax>h{NlWLA7;;6TcQHA>UJB$KNk74T1xNWh9)kwK~wX0m|Jo_Z;g;>^E4-k4R zRj#pQb-Hg&dAh}*=2;JY*aiNZzT=IU&v|lQY%Q|=^V5pvTR7^t9+@+ST&sr!J1Y9a z514dYZn5rg6@4Cy6P`-?!3Y& z?B*5zw!mTiD2)>f@3XYrW^9V-@%YFkE_;PCyCJ7*?_3cR%tHng9%ZpIU}LJM=a+0s z(SDDLvcVa~b9O!cVL8)Q{d^R^(bbG=Ia$)dVN_tGMee3PMssZ7Z;c^Vg_1CjZYTnq z)wnF8?=-MmqVOMX!iE?YDvHCN?%TQtKJMFHp$~kX4}jZ;EDqP$?jqJZjoa2PM@$uZ zF4}iab1b5ep)L;jdegC3{K4VnCH#OV;pRcSa(&Nm50ze-yZ8*cGv;@+N+A?ncc^2z9~|(xFhwOHmPW@ zR5&)E^YKQj@`g=;zJ_+CLamsPuvppUr$G1#9urUj+p-mPW_QSSHkPMS!52t>Hqy|g z_@Yu3z%|wE=uYq8G>4`Q!4zivS}+}{m5Zjr7kMRGn_p&hNf|pc&f9iQ`^%78rl#~8 z;os@rpMA{ZioY~(Rm!Wf#Wx##A0PthOI341QiJ=G*#}pDAkDm+{0kz&*NB?rC0-)glB{0_Tq*^o zVS1>3REsv*Qb;qg!G^9;VoK)P*?f<*H&4Su1=}bP^Y<2PwFpoqw#up4IgX3L z`w~8jsFCI3k~Y9g(Y9Km`y$0FS5vHb)kb)Jb6q-9MbO{Hbb zxg?IWQ1ZIGgE}wKm{axO6CCh~4DyoFU+i1xn#oyfe+<{>=^B5tm!!*1M?AW8c=6g+%2Ft97_Hq&ZmOGvqGQ!Bn<_Vw`0DRuDoB6q8ME<;oL4kocr8E$NGoLI zXWmI7Af-DR|KJw!vKp2SI4W*x%A%5BgDu%8%Iato+pWo5`vH@!XqC!yK}KLzvfS(q z{!y(S-PKbk!qHsgVyxKsQWk_8HUSSmslUA9nWOjkKn0%cwn%yxnkfxn?Y2rysXKS=t-TeI%DN$sQ{lcD!(s>(4y#CSxZ4R} zFDI^HPC_l?uh_)-^ppeYRkPTPu~V^0Mt}#jrTL1Q(M;qVt4zb(L|J~sxx7Lva9`mh zz!#A9tA*6?q)xThc7(gB2Ryam$YG4qlh00c}r&$y6u zIN#Qxn{7RKJ+_r|1G1KEv!&uKfXpOVZ8tK{M775ws%nDyoZ?bi3NufNbZs)zqXiqc zqOsK@^OnlFMAT&mO3`@3nZP$3lLF;ds|;Z{W(Q-STa2>;)tjhR17OD|G>Q#zJHb*> zMO<{WIgB%_4MG0SQi2;%f0J8l_FH)Lfaa>*GLobD#AeMttYh4Yfg22@q4|Itq};NB z8;o*+@APqy@fPgrc&PTbGEwdEK=(x5K!If@R$NiO^7{#j9{~w=RBG)ZkbOw@$7Nhl zyp{*&QoVBd5lo{iwl2gfyip@}IirZK;ia(&ozNl!-EEYc=QpYH_= zJkv7gA{!n4up6$CrzDJIBAdC7D5D<_VLH*;OYN>_Dx3AT`K4Wyx8Tm{I+xplKP6k7 z2sb!i7)~%R#J0$|hK?~=u~rnH7HCUpsQJujDDE*GD`qrWWog+C+E~GGy|Hp_t4--} zrxtrgnPh}r=9o}P6jpAQuDN}I*GI`8&%Lp-C0IOJt#op)}XSr!ova@w{jG2V=?GXl3zEJJFXg)U3N>BQP z*Lb@%Mx|Tu;|u>$-K(q^-HG!EQ3o93%w(A7@ngGU)HRWoO&&^}U$5x+T&#zri>6ct zXOB#EF-;z3j311K`jrYyv6pOPF=*`SOz!ack=DuEi({UnAkL5H)@R?YbRKAeP|06U z?-Ns0ZxD0h9D8)P66Sq$w-yF+1hEVTaul%&=kKDrQtF<$RnQPZ)ezm1`aHIjAY=!S z`%vboP`?7mItgEo4w50C*}Ycqp9_3ZEr^F1;cEhkb`BNhbc6PvnXu@wi=AoezF4~K zkxx%ps<8zb=wJ+9I8o#do)&{(=yAlNdduaDn!=xGSiuo~fLw~Edw$6;l-qaq#Z7?# zGrdU(Cf-V@$x>O%yRc6!C1Vf`b19ly;=mEu8u9|zitcG^O`lbNh}k=$%a)UHhDwTEKis2yc4rBGR>l*(B$AC7ung&ssaZGkY-h(fpwcPyJSx*9EIJMRKbMP9}$nVrh6$g-Q^5Cw)BeWqb-qi#37ZXKL!GR;ql)~ z@PP*-oP?T|ThqlGKR84zi^CN z4TZ1A)7vL>ivoL2EU_~xl-P{p+sE}9CRwGJDKy{>0KP+gj`H9C+4fUMPnIB1_D`A- z$1`G}g0lQmqMN{Y&8R*$xYUB*V}dQPxGVZQ+rH!DVohIoTbh%#z#Tru%Px@C<=|og zGDDwGq7yz`%^?r~6t&>x*^We^tZ4!E4dhwsht#Pb1kCY{q#Kv;z%Dp#Dq;$vH$-(9 z8S5tutZ}&JM2Iw&Y-7KY4h5BBvS=Ove0#+H2qPdR)WyI zYcj)vB=MA{7T|3Ij_PN@FM@w(C9ANBq&|NoW30ccr~i#)EcH)T^3St~rJ0HKKd4wr z@_+132;Bj+>UC@h)Ap*8B4r5A1lZ!Dh%H7&&hBnlFj@eayk=VD*i5AQc z$uN8YG#PL;cuQa)Hyt-}R?&NAE1QT>svJDKt*)AQOZAJ@ zyxJoBebiobHeFlcLwu_iI&NEZuipnOR;Tn;PbT1Mt-#5v5b*8ULo7m)L-eti=UcGf zRZXidmxeFgY!y80-*PH-*=(-W+fK%KyUKpg$X@tuv``tXj^*4qq@UkW$ZrAo%+hay zU@a?z&2_@y)o@D!_g>NVxFBO!EyB&6Z!nd4=KyDP^hl!*(k{dEF6@NkXztO7gIh zQ&PC+p-8WBv;N(rpfKdF^@Z~|E6pa)M1NBUrCZvLRW$%N%xIbv^uv?=C!=dDVq3%* zgvbEBnG*JB*@vXx8>)7XL*!{1Jh=#2UrByF7U?Rj_}VYw88BwqefT_cCTv8aTrRVjnn z1HNCF=44?*&gs2`vCGJVHX@kO z240eo#z+FhI0=yy6NHQwZs}a+J~4U-6X`@ zZ7j+tb##m`x%J66$a9qXDHG&^kp|GkFFMmjD(Y-k_ClY~N$H|n@NkSDz=gg?*2ga5 z)+f)MEY>2Lp15;~o`t`qj;S>BaE;%dv@Ux11yq}I(k|o&`5UZFUHn}1kE^gIK@qV& z!S2IhyU;->VfA4Qb}m7YnkIa9%z{l~iPWo2YPk-`hy2-Eg=6E$21plQA5W2qMZDFU z-a-@Dndf%#on6chT`dOKnU9}BJo|kJwgGC<^nfo34zOKH96LbWY7@Wc%EoFF=}`VU zksP@wd%@W;-p!e^&-)N7#oR331Q)@9cx=mOoU?_Kih2!Le*8fhsZ8Qvo6t2vt+UOZ zw|mCB*t2%z21YqL>whu!j?s~}-L`OS+jdg1(XnmYw$rg~r(?5Y+qTg`$F}q3J?GtL z@BN&8#`u2RqkdG4yGGTus@7U_%{6C{XAhFE!2SelH?KtMtX@B1GBhEIDL-Bj#~{4! zd}p7!#XE9Lt;sy@p5#Wj*jf8zGv6tTotCR2X$EVOOup;GnRPRVU5A6N@Lh8?eA7k? zn~hz&gY;B0ybSpF?qwQ|sv_yO=8}zeg2$0n3A8KpE@q26)?707pPw?H76lCpjp=5r z6jjp|auXJDnW}uLb6d7rsxekbET9(=zdTqC8(F5@NNqII2+~yB;X5iJNQSiv`#ozm zf&p!;>8xAlwoxUC3DQ#!31ylK%VrcwS<$WeCY4V63V!|221oj+5#r}fGFQ}|uwC0) zNl8(CF}PD`&Sj+p{d!B&&JtC+VuH z#>US`)YQrhb6lIAYb08H22y(?)&L8MIQsA{26X`R5Km{YU)s!x(&gIsjDvq63@X`{ z=7{SiH*_ZsPME#t2m|bS76Uz*z{cpp1m|s}HIX}Ntx#v7Eo!1%G9__4dGSGl`p+xi zZ!VK#Qe;Re=9bqXuW+0DSP{uZ5-QXrNn-7qW19K0qU}OhVru7}3vqsG?#D67 zb}crN;QwsH*vymw(maZr_o|w&@sQki(X+D)gc5Bt&@iXisFG;eH@5d43~Wxq|HO(@ zV-rip4n#PEkHCWCa5d?@cQp^B;I-PzOfag|t-cuvTapQ@MWLmh*41NH`<+A+JGyKX zyYL6Ba7qqa5j@3lOk~`OMO7f0!@FaOeZxkbG@vXP(t3#U*fq8=GAPqUAS>vW2uxMk{a(<0=IxB;# zMW;M+owrHaZBp`3{e@7gJCHP!I(EeyGFF;pdFPdeP+KphrulPSVidmg#!@W`GpD&d z9p6R`dpjaR2E1Eg)Ws{BVCBU9-aCgN57N~uLvQZH`@T+2eOBD%73rr&sV~m#2~IZx zY_8f8O;XLu2~E3JDXnGhFvsyb^>*!D>5EtlKPe%kOLv6*@=Jpci`8h0z?+fbBUg_7 zu6DjqO=$SjAv{|Om5)nz41ZkS4E_|fk%NDY509VV5yNeo%O|sb>7C#wj8mL9cEOFh z>nDz%?vb!h*!0dHdnxDA>97~EoT~!N40>+)G2CeYdOvJr5^VnkGz)et&T9hrD(VAgCAJjQ7V$O?csICB*HFd^k@$M5*v$PZJD-OVL?Ze(U=XGqZPVG8JQ z<~ukO%&%nNXYaaRibq#B1KfW4+XMliC*Tng2G(T1VvP;2K~;b$EAqthc${gjn_P!b zs62UT(->A>!ot}cJXMZHuy)^qfqW~xO-In2);e>Ta{LD6VG2u&UT&a@>r-;4<)cJ9 zjpQThb4^CY)Ev0KR7TBuT#-v}W?Xzj{c7$S5_zJA57Qf=$4^npEjl9clH0=jWO8sX z3Fuu0@S!WY>0XX7arjH`?)I<%2|8HfL!~#c+&!ZVmhbh`wbzy0Ux|Jpy9A{_7GGB0 zadZ48dW0oUwUAHl%|E-Q{gA{z6TXsvU#Hj09<7i)d}wa+Iya)S$CVwG{4LqtB>w%S zKZx(QbV7J9pYt`W4+0~f{hoo5ZG<0O&&5L57oF%hc0xGJ@Zrg_D&lNO=-I^0y#3mxCSZFxN2-tN_mU@7<@PnWG?L5OSqkm8TR!`| zRcTeWH~0z1JY^%!N<(TtxSP5^G9*Vw1wub`tC-F`=U)&sJVfvmh#Pi`*44kSdG};1 zJbHOmy4Ot|%_?@$N?RA9fF?|CywR8Sf(SCN_luM8>(u0NSEbKUy7C(Sk&OuWffj)f za`+mo+kM_8OLuCUiA*CNE|?jra$M=$F3t+h-)?pXz&r^F!ck;r##`)i)t?AWq-9A9 zSY{m~TC1w>HdEaiR*%j)L);H{IULw)uxDO>#+WcBUe^HU)~L|9#0D<*Ld459xTyew zbh5vCg$a>`RCVk)#~ByCv@Ce!nm<#EW|9j><#jQ8JfTmK#~jJ&o0Fs9jz0Ux{svdM4__<1 zrb>H(qBO;v(pXPf5_?XDq!*3KW^4>(XTo=6O2MJdM^N4IIcYn1sZZpnmMAEdt}4SU zPO54j2d|(xJtQ9EX-YrlXU1}6*h{zjn`in-N!Ls}IJsG@X&lfycsoCemt_Ym(PXhv zc*QTnkNIV=Ia%tg%pwJtT^+`v8ng>;2~ps~wdqZSNI7+}-3r+#r6p`8*G;~bVFzg= z!S3&y)#iNSUF6z;%o)%h!ORhE?CUs%g(k2a-d576uOP2@QwG-6LT*G!I$JQLpd`cz z-2=Brr_+z96a0*aIhY2%0(Sz=|D`_v_7h%Yqbw2)8@1DwH4s*A82krEk{ zoa`LbCdS)R?egRWNeHV8KJG0Ypy!#}kslun?67}^+J&02!D??lN~t@;h?GS8#WX`)6yC**~5YNhN_Hj}YG<%2ao^bpD8RpgV|V|GQwlL27B zEuah|)%m1s8C6>FLY0DFe9Ob66fo&b8%iUN=y_Qj;t3WGlNqP9^d#75ftCPA*R4E8 z)SWKBKkEzTr4JqRMEs`)0;x8C35yRAV++n(Cm5++?WB@ya=l8pFL`N0ag`lWhrYo3 zJJ$< zQ*_YAqIGR*;`VzAEx1Pd4b3_oWtdcs7LU2#1#Ls>Ynvd8k^M{Ef?8`RxA3!Th-?ui{_WJvhzY4FiPxA?E4+NFmaC-Uh*a zeLKkkECqy>Qx&1xxEhh8SzMML=8VP}?b*sgT9ypBLF)Zh#w&JzP>ymrM?nnvt!@$2 zh>N$Q>mbPAC2kNd&ab;FkBJ}39s*TYY0=@e?N7GX>wqaM>P=Y12lciUmve_jMF0lY zBfI3U2{33vWo(DiSOc}!5##TDr|dgX1Uojq9!vW3$m#zM_83EGsP6&O`@v-PDdO3P z>#!BEbqpOXd5s?QNnN!p+92SHy{sdpePXHL{d@c6UilT<#~I!tH$S(~o}c#(j<2%! zQvm}MvAj-95Ekx3D4+|e%!?lO(F+DFw9bxb-}rsWQl)b44###eUg4N?N-P(sFH2hF z`{zu?LmAxn2=2wCE8?;%ZDi#Y;Fzp+RnY8fWlzVz_*PDO6?Je&aEmuS>=uCXgdP6r zoc_JB^TA~rU5*geh{G*gl%_HnISMS~^@{@KVC;(aL^ZA-De+1zwUSXgT>OY)W?d6~ z72znET0m`53q%AVUcGraYxIcAB?OZA8AT!uK8jU+=t;WneL~|IeQ>$*dWa#x%rB(+ z5?xEkZ&b{HsZ4Ju9TQ|)c_SIp`7r2qMJgaglfSBHhl)QO1aNtkGr0LUn{@mvAt=}nd7#>7ru}&I)FNsa*x?Oe3-4G`HcaR zJ}c%iKlwh`x)yX1vBB;-Nr=7>$~(u=AuPX2#&Eh~IeFw%afU+U)td0KC!pHd zyn+X$L|(H3uNit-bpn7%G%{&LsAaEfEsD?yM<;U2}WtD4KuVKuX=ec9X zIe*ibp1?$gPL7<0uj*vmj2lWKe`U(f9E{KVbr&q*RsO;O>K{i-7W)8KG5~~uS++56 zm@XGrX@x+lGEjDQJp~XCkEyJG5Y57omJhGN{^2z5lj-()PVR&wWnDk2M?n_TYR(gM zw4kQ|+i}3z6YZq8gVUN}KiYre^sL{ynS}o{z$s&I z{(rWaLXxcQ=MB(Cz7W$??Tn*$1y(7XX)tv;I-{7F$fPB%6YC7>-Dk#=Y8o1=&|>t5 zV_VVts>Eb@)&4%m}!K*WfLoLl|3FW)V~E1Z!yu`Sn+bAP5sRDyu7NEbLt?khAyz-ZyL-}MYb&nQ zU16f@q7E1rh!)d%f^tTHE3cVoa%Xs%rKFc|temN1sa)aSlT*)*4k?Z>b3NP(IRXfq zlB^#G6BDA1%t9^Nw1BD>lBV(0XW5c?l%vyB3)q*;Z5V~SU;HkN;1kA3Nx!$!9wti= zB8>n`gt;VlBt%5xmDxjfl0>`K$fTU-C6_Z;!A_liu0@Os5reMLNk;jrlVF^FbLETI zW+Z_5m|ozNBn7AaQ<&7zk}(jmEdCsPgmo%^GXo>YYt82n&7I-uQ%A;k{nS~VYGDTn zlr3}HbWQG6xu8+bFu^9%%^PYCbkLf=*J|hr>Sw+#l(Y#ZGKDufa#f-f0k-{-XOb4i zwVG1Oa0L2+&(u$S7TvedS<1m45*>a~5tuOZ;3x%!f``{=2QQlJk|b4>NpD4&L+xI+ z+}S(m3}|8|Vv(KYAGyZK5x*sgwOOJklN0jsq|BomM>OuRDVFf_?cMq%B*iQ*&|vS9 zVH7Kh)SjrCBv+FYAE=$0V&NIW=xP>d-s7@wM*sdfjVx6-Y@=~>rz%2L*rKp|*WXIz z*vR^4tV&7MQpS9%{9b*>E9d_ls|toL7J|;srnW{l-}1gP_Qr-bBHt=}PL@WlE|&KH zCUmDLZb%J$ZzNii-5VeygOM?K8e$EcK=z-hIk63o4y63^_*RdaitO^THC{boKstphXZ2Z+&3ToeLQUG(0Frs?b zCxB+65h7R$+LsbmL51Kc)pz_`YpGEzFEclzb=?FJ=>rJwgcp0QH-UuKRS1*yCHsO) z-8t?Zw|6t($Eh&4K+u$I7HqVJBOOFCRcmMMH};RX_b?;rnk`rz@vxT_&|6V@q0~Uk z9ax|!pA@Lwn8h7syrEtDluZ6G!;@=GL> zse#PRQrdDs=qa_v@{Wv(3YjYD0|qocDC;-F~&{oaTP?@pi$n z1L6SlmFU2~%)M^$@C(^cD!y)-2SeHo3t?u3JiN7UBa7E2 z;<+_A$V084@>&u)*C<4h7jw9joHuSpVsy8GZVT;(>lZ(RAr!;)bwM~o__Gm~exd`K zKEgh2)w?ReH&syI`~;Uo4`x4$&X+dYKI{e`dS~bQuS|p zA`P_{QLV3r$*~lb=9vR^H0AxK9_+dmHX}Y} zIV*#65%jRWem5Z($ji{!6ug$En4O*=^CiG=K zp4S?+xE|6!cn$A%XutqNEgUqYY3fw&N(Z6=@W6*bxdp~i_yz5VcgSj=lf-6X1Nz75 z^DabwZ4*70$$8NsEy@U^W67tcy7^lNbu;|kOLcJ40A%J#pZe0d#n zC{)}+p+?8*ftUlxJE*!%$`h~|KZSaCb=jpK3byAcuHk7wk@?YxkT1!|r({P*KY^`u z!hw#`5$JJZGt@nkBK_nwWA31_Q9UGvv9r-{NU<&7HHMQsq=sn@O?e~fwl20tnSBG* zO%4?Ew6`aX=I5lqmy&OkmtU}bH-+zvJ_CFy z_nw#!8Rap5Wcex#5}Ldtqhr_Z$}@jPuYljTosS1+WG+TxZ>dGeT)?ZP3#3>sf#KOG z0)s%{cEHBkS)019}-1A2kd*it>y65-C zh7J9zogM74?PU)0c0YavY7g~%j%yiWEGDb+;Ew5g5Gq@MpVFFBNOpu0x)>Yn>G6uo zKE%z1EhkG_N5$a8f6SRm(25iH#FMeaJ1^TBcBy<04ID47(1(D)q}g=_6#^V@yI?Y&@HUf z`;ojGDdsvRCoTmasXndENqfWkOw=#cV-9*QClpI03)FWcx(m5(P1DW+2-{Hr-`5M{v##Zu-i-9Cvt;V|n)1pR^y ztp3IXzHjYWqabuPqnCY9^^;adc!a%Z35VN~TzwAxq{NU&Kp35m?fw_^D{wzB}4FVXX5Zk@#={6jRh%wx|!eu@Xp;%x+{2;}!&J4X*_SvtkqE#KDIPPn@ z5BE$3uRlb>N<2A$g_cuRQM1T#5ra9u2x9pQuqF1l2#N{Q!jVJ<>HlLeVW|fN|#vqSnRr<0 zTVs=)7d`=EsJXkZLJgv~9JB&ay16xDG6v(J2eZy;U%a@EbAB-=C?PpA9@}?_Yfb&) zBpsih5m1U9Px<+2$TBJ@7s9HW>W){i&XKLZ_{1Wzh-o!l5_S+f$j^RNYo85}uVhN# zq}_mN-d=n{>fZD2Lx$Twd2)}X2ceasu91}n&BS+4U9=Y{aZCgV5# z?z_Hq-knIbgIpnkGzJz-NW*=p?3l(}y3(aPCW=A({g9CpjJfYuZ%#Tz81Y)al?!S~ z9AS5#&nzm*NF?2tCR#|D-EjBWifFR=da6hW^PHTl&km-WI9*F4o>5J{LBSieVk`KO z2(^9R(zC$@g|i3}`mK-qFZ33PD34jd_qOAFj29687wCUy>;(Hwo%Me&c=~)V$ua)V zsaM(aThQ3{TiM~;gTckp)LFvN?%TlO-;$y+YX4i`SU0hbm<})t0zZ!t1=wY&j#N>q zONEHIB^RW6D5N*cq6^+?T}$3m|L{Fe+L!rxJ=KRjlJS~|z-&CC{#CU8`}2|lo~)<| zk?Wi1;Cr;`?02-C_3^gD{|Ryhw!8i?yx5i0v5?p)9wZxSkwn z3C;pz25KR&7{|rc4H)V~y8%+6lX&KN&=^$Wqu+}}n{Y~K4XpI-#O?L=(2qncYNePX zTsB6_3`7q&e0K67=Kg7G=j#?r!j0S^w7;0?CJbB3_C4_8X*Q%F1%cmB{g%XE&|IA7 z(#?AeG{l)s_orNJp!$Q~qGrj*YnuKlV`nVdg4vkTNS~w$4d^Oc3(dxi(W5jq0e>x} z(GN1?u2%Sy;GA|B%Sk)ukr#v*UJU%(BE9X54!&KL9A^&rR%v zIdYt0&D59ggM}CKWyxGS@ z>T#})2Bk8sZMGJYFJtc>D#k0+Rrrs)2DG;(u(DB_v-sVg=GFMlSCx<&RL;BH}d6AG3VqP!JpC0Gv6f8d|+7YRC@g|=N=C2 zo>^0CE0*RW?W))S(N)}NKA)aSwsR{1*rs$(cZIs?nF9)G*bSr%%SZo^YQ|TSz={jX z4Z+(~v_>RH0(|IZ-_D_h@~p_i%k^XEi+CJVC~B zsPir zA0Jm2yIdo4`&I`hd%$Bv=Rq#-#bh{Mxb_{PN%trcf(#J3S1UKDfC1QjH2E;>wUf5= ze8tY9QSYx0J;$JUR-0ar6fuiQTCQP#P|WEq;Ez|*@d?JHu-(?*tTpGHC+=Q%H>&I> z*jC7%nJIy+HeoURWN%3X47UUusY2h7nckRxh8-)J61Zvn@j-uPA@99|y48pO)0XcW zX^d&kW^p7xsvdX?2QZ8cEUbMZ7`&n{%Bo*xgFr4&fd#tHOEboQos~xm8q&W;fqrj} z%KYnnE%R`=`+?lu-O+J9r@+$%YnqYq!SVs>xp;%Q8p^$wA~oynhnvIFp^)Z2CvcyC zIN-_3EUHW}1^VQ0;Oj>q?mkPx$Wj-i7QoXgQ!HyRh6Gj8p~gH22k&nmEqUR^)9qni{%uNeV{&0-H60C zibHZtbV=8=aX!xFvkO}T@lJ_4&ki$d+0ns3FXb+iP-VAVN`B7f-hO)jyh#4#_$XG%Txk6M<+q6D~ zi*UcgRBOoP$7P6RmaPZ2%MG}CMfs=>*~(b97V4+2qdwvwA@>U3QQAA$hiN9zi%Mq{ z*#fH57zUmi)GEefh7@`Uy7?@@=BL7cXbd{O9)*lJh*v!@ z-6}p9u0AreiGauxn7JBEa-2w&d=!*TLJ49`U@D7%2ppIh)ynMaAE2Q4dl@47cNu{9 z&3vT#pG$#%hrXzXsj=&Ss*0;W`Jo^mcy4*L8b^sSi;H{*`zW9xX2HAtQ*sO|x$c6UbRA(7*9=;D~(%wfo(Z6#s$S zuFk`dr%DfVX5KC|Af8@AIr8@OAVj=6iX!~8D_P>p7>s!Hj+X0_t}Y*T4L5V->A@Zx zcm1wN;TNq=h`5W&>z5cNA99U1lY6+!!u$ib|41VMcJk8`+kP{PEOUvc@2@fW(bh5pp6>C3T55@XlpsAd#vn~__3H;Dz2w=t9v&{v*)1m4)vX;4 zX4YAjM66?Z7kD@XX{e`f1t_ZvYyi*puSNhVPq%jeyBteaOHo7vOr8!qqp7wV;)%jtD5>}-a?xavZ;i|2P3~7c)vP2O#Fb`Y&Kce zQNr7%fr4#S)OOV-1piOf7NgQvR{lcvZ*SNbLMq(olrdDC6su;ubp5un!&oT=jVTC3uTw7|r;@&y*s)a<{J zkzG(PApmMCpMmuh6GkM_`AsBE@t~)EDcq1AJ~N@7bqyW_i!mtHGnVgBA`Dxi^P93i z5R;}AQ60wy=Q2GUnSwz+W6C^}qn`S-lY7=J(3#BlOK%pCl=|RVWhC|IDj1E#+|M{TV0vE;vMZLy7KpD1$Yk zi0!9%qy8>CyrcRK`juQ)I};r)5|_<<9x)32b3DT1M`>v^ld!yabX6@ihf`3ZVTgME zfy(l-ocFuZ(L&OM4=1N#Mrrm_<>1DZpoWTO70U8+x4r3BpqH6z@(4~sqv!A9_L}@7 z7o~;|?~s-b?ud&Wx6==9{4uTcS|0-p@dKi0y#tPm2`A!^o3fZ8Uidxq|uz2vxf;wr zM^%#9)h^R&T;}cxVI(XX7kKPEVb);AQO?cFT-ub=%lZPwxefymBk+!H!W(o(>I{jW z$h;xuNUr#^0ivvSB-YEbUqe$GLSGrU$B3q28&oA55l)ChKOrwiTyI~e*uN;^V@g-Dm4d|MK!ol8hoaSB%iOQ#i_@`EYK_9ZEjFZ8Ho7P^er z^2U6ZNQ{*hcEm?R-lK)pD_r(e=Jfe?5VkJ$2~Oq^7YjE^5(6a6Il--j@6dBHx2Ulq z!%hz{d-S~i9Eo~WvQYDt7O7*G9CP#nrKE#DtIEbe_uxptcCSmYZMqT2F}7Kw0AWWC zPjwo0IYZ6klc(h9uL|NY$;{SGm4R8Bt^^q{e#foMxfCSY^-c&IVPl|A_ru!ebwR#7 z3<4+nZL(mEsU}O9e`^XB4^*m)73hd04HH%6ok^!;4|JAENnEr~%s6W~8KWD)3MD*+ zRc46yo<}8|!|yW-+KulE86aB_T4pDgL$XyiRW(OOcnP4|2;v!m2fB7Hw-IkY#wYfF zP4w;k-RInWr4fbz=X$J;z2E8pvAuy9kLJUSl8_USi;rW`kZGF?*Ur%%(t$^{Rg!=v zg;h3@!Q$eTa7S0#APEDHLvK%RCn^o0u!xC1Y0Jg!Baht*a4mmKHy~88md{YmN#x) zBOAp_i-z2h#V~*oO-9k(BizR^l#Vm%uSa^~3337d;f=AhVp?heJ)nlZGm`}D(U^2w z#vC}o1g1h?RAV^90N|Jd@M00PoNUPyA?@HeX0P7`TKSA=*4s@R;Ulo4Ih{W^CD{c8 ze(ipN{CAXP(KHJ7UvpOc@9SUAS^wKo3h-}BDZu}-qjdNlVtp^Z{|CxKOEo?tB}-4; zEXyDzGbXttJ3V$lLo-D?HYwZm7vvwdRo}P#KVF>F|M&eJ44n*ZO~0)#0e0Vy&j00I z{%IrnUvKp70P?>~J^$^0Wo%>le>re2ZSvRfes@dC-*e=DD1-j%<$^~4^4>Id5w^Fr z{RWL>EbUCcyC%1980kOYqZAcgdz5cS8c^7%vvrc@CSPIx;X=RuodO2dxk17|am?HJ@d~Mp_l8H?T;5l0&WGFoTKM{eP!L-a0O8?w zgBPhY78tqf^+xv4#OK2I#0L-cSbEUWH2z+sDur85*!hjEhFfD!i0Eyr-RRLFEm5(n z-RV6Zf_qMxN5S6#8fr9vDL01PxzHr7wgOn%0Htmvk9*gP^Um=n^+7GLs#GmU&a#U^4jr)BkIubQO7oUG!4CneO2Ixa`e~+Jp9m{l6apL8SOqA^ zvrfEUPwnHQ8;yBt!&(hAwASmL?Axitiqvx%KZRRP?tj2521wyxN3ZD9buj4e;2y6U zw=TKh$4%tt(eh|y#*{flUJ5t4VyP*@3af`hyY^YU3LCE3Z|22iRK7M7E;1SZVHbXF zKVw!L?2bS|kl7rN4(*4h2qxyLjWG0vR@`M~QFPsf^KParmCX;Gh4OX6Uy9#4e_%oK zv1DRnfvd$pu(kUoV(MmAc09ckDiuqS$a%!AQ1Z>@DM#}-yAP$l`oV`BDYpkqpk(I|+qk!yoo$TwWr6dRzLy(c zi+qbVlYGz0XUq@;Fm3r~_p%by)S&SVWS+wS0rC9bk^3K^_@6N5|2rtF)wI>WJ=;Fz zn8$h<|Dr%kN|nciMwJAv;_%3XG9sDnO@i&pKVNEfziH_gxKy{l zo`2m4rnUT(qenuq9B0<#Iy(RPxP8R)=5~9wBku=%&EBoZ82x1GlV<>R=hIqf0PK!V zw?{z9e^B`bGyg2nH!^x}06oE%J_JLk)^QyHLipoCs2MWIqc>vaxsJj(=gg1ZSa=u{ zt}od#V;e7sA4S(V9^<^TZ#InyVBFT(V#$fvI7Q+pgsr_2X`N~8)IOZtX}e(Bn(;eF zsNj#qOF_bHl$nw5!ULY{lNx@93Fj}%R@lewUuJ*X*1$K`DNAFpE z7_lPE+!}uZ6c?+6NY1!QREg#iFy=Z!OEW}CXBd~wW|r_9%zkUPR0A3m+@Nk%4p>)F zXVut7$aOZ6`w}%+WV$te6-IX7g2yms@aLygaTlIv3=Jl#Nr}nN zp|vH-3L03#%-1-!mY`1z?+K1E>8K09G~JcxfS)%DZbteGQnQhaCGE2Y<{ut#(k-DL zh&5PLpi9x3$HM82dS!M?(Z zEsqW?dx-K_GMQu5K54pYJD=5+Rn&@bGjB?3$xgYl-|`FElp}?zP&RAd<522c$Rv6} zcM%rYClU%JB#GuS>FNb{P2q*oHy}UcQ-pZ2UlT~zXt5*k-ZalE(`p7<`0n7i(r2k{ zb84&^LA7+aW1Gx5!wK!xTbw0slM?6-i32CaOcLC2B>ZRI16d{&-$QBEu1fKF0dVU>GTP05x2>Tmdy`75Qx! z^IG;HB9V1-D5&&)zjJ&~G}VU1-x7EUlT3QgNT<&eIDUPYey$M|RD6%mVkoDe|;2`8Z+_{0&scCq>Mh3hj|E*|W3;y@{$qhu77D)QJ` znD9C1AHCKSAHQqdWBiP`-cAjq7`V%~JFES1=i-s5h6xVT<50kiAH_dn0KQB4t*=ua zz}F@mcKjhB;^7ka@WbSJFZRPeYI&JFkpJ-!B z!ju#!6IzJ;D@$Qhvz9IGY5!%TD&(db3<*sCpZ?U#1^9RWQ zs*O-)j!E85SMKtoZzE^8{w%E0R0b2lwwSJ%@E}Lou)iLmPQyO=eirG8h#o&E4~eew z;h><=|4m0$`ANTOixHQOGpksXlF0yy17E&JksB4_(vKR5s$Ve+i;gco2}^RRJI+~R zWJ82WGigLIUwP!uSELh3AAs9HmY-kz=_EL-w|9}noKE#(a;QBpEx9 z4BT-zY=6dJT>72Hkz=9J1E=}*MC;zzzUWb@x(Ho8cU_aRZ?fxse5_Ru2YOvcr?kg&pt@v;{ai7G--k$LQtoYj+Wjk+nnZty;XzANsrhoH#7=xVqfPIW(p zX5{YF+5=k4_LBnhLUZxX*O?29olfPS?u*ybhM_y z*XHUqM6OLB#lyTB`v<BZ&YRs$N)S@5Kn_b3;gjz6>fh@^j%y2-ya({>Hd@kv{CZZ2e)tva7gxLLp z`HoGW);eRtov~Ro5tetU2y72~ zQh>D`@dt@s^csdfN-*U&o*)i3c4oBufCa0e|BwT2y%Y~=U7A^ny}tx zHwA>Wm|!SCko~UN?hporyQHRUWl3djIc722EKbTIXQ6>>iC!x+cq^sUxVSj~u)dsY zW8QgfZlE*2Os%=K;_vy3wx{0u!2%A)qEG-$R^`($%AOfnA^LpkB_}Dd7AymC)zSQr z>C&N8V57)aeX8ap!|7vWaK6=-3~ko9meugAlBKYGOjc#36+KJwQKRNa_`W@7;a>ot zdRiJkz?+QgC$b}-Owzuaw3zBVLEugOp6UeMHAKo2$m4w zpw?i%Lft^UtuLI}wd4(-9Z^*lVoa}11~+0|Hs6zAgJ01`dEA&^>Ai=mr0nC%eBd_B zzgv2G_~1c1wr*q@QqVW*Wi1zn=}KCtSwLjwT>ndXE_Xa22HHL_xCDhkM( zhbw+j4uZM|r&3h=Z#YrxGo}GX`)AZyv@7#7+nd-D?BZV>thtc|3jt30j$9{aIw9)v zDY)*fsSLPQTNa&>UL^RWH(vpNXT7HBv@9=*=(Q?3#H*crA2>KYx7Ab?-(HU~a275)MBp~`P)hhzSsbj|d`aBe(L*(;zif{iFJu**ZR zkL-tPyh!#*r-JVQJq>5b0?cCy!uSKef+R=$s3iA7*k*_l&*e!$F zYwGI;=S^0)b`mP8&Ry@{R(dPfykD&?H)na^ihVS7KXkxb36TbGm%X1!QSmbV9^#>A z-%X>wljnTMU0#d;tpw?O1W@{X-k*>aOImeG z#N^x?ehaaQd}ReQykp>i;92q@%$a!y1PNyPYDIvMm& zyYVwn;+0({W@3h(r&i#FuCDE)AC(y&Vu>4?1@j0|CWnhHUx4|zL7cdaA32RSk?wl% zMK^n42@i5AU>f70(huWfOwaucbaToxj%+)7hnG^CjH|O`A}+GHZyQ-X57(WuiyRXV zPf>0N3GJ<2Myg!sE4XJY?Z7@K3ZgHy8f7CS5ton0Eq)Cp`iLROAglnsiEXpnI+S8; zZn>g2VqLxi^p8#F#Laf3<00AcT}Qh&kQnd^28u!9l1m^`lfh9+5$VNv=?(~Gl2wAl zx(w$Z2!_oESg_3Kk0hUsBJ<;OTPyL(?z6xj6LG5|Ic4II*P+_=ac7KRJZ`(k2R$L# zv|oWM@116K7r3^EL*j2ktjEEOY9c!IhnyqD&oy7+645^+@z5Y|;0+dyR2X6^%7GD* zXrbPqTO}O={ z4cGaI#DdpP;5u?lcNb($V`l>H7k7otl_jQFu1hh>=(?CTPN#IPO%O_rlVX}_Nq;L< z@YNiY>-W~&E@=EC5%o_z<^3YEw)i_c|NXxHF{=7U7Ev&C`c^0Z4-LGKXu*Hkk&Av= zG&RAv{cR7o4${k~f{F~J48Ks&o(D@j-PQ2`LL@I~b=ifx3q!p6`d>~Y!<-^mMk3)e zhi1;(YLU5KH}zzZNhl^`0HT(r`5FfmDEzxa zk&J7WQ|!v~TyDWdXQ)!AN_Y%xM*!jv^`s)A`|F%;eGg27KYsrCE2H}7*r)zvum6B{ z$k5Har9pv!dcG%f|3hE(#hFH+12RZPycVi?2y`-9I7JHryMn3 z9Y8?==_(vOAJ7PnT<0&85`_jMD0#ipta~Q3M!q5H1D@Nj-YXI$W%OQplM(GWZ5Lpq z-He6ul|3<;ZQsqs!{Y7x`FV@pOQc4|N;)qgtRe(Uf?|YqZv^$k8On7DJ5>f2%M=TV zw~x}9o=mh$JVF{v4H5Su1pq66+mhTG6?F>Do}x{V(TgFwuLfvNP^ijkrp5#s4UT!~ zEU7pr8aA)2z1zb|X9IpmJykQcqI#(rS|A4&=TtWu@g^;JCN`2kL}%+K!KlgC z>P)v+uCeI{1KZpewf>C=?N7%1e10Y3pQCZST1GT5fVyB1`q)JqCLXM zSN0qlreH1=%Zg-5`(dlfSHI&2?^SQdbEE&W4#%Eve2-EnX>NfboD<2l((>>34lE%) zS6PWibEvuBG7)KQo_`?KHSPk+2P;`}#xEs}0!;yPaTrR#j(2H|#-CbVnTt_?9aG`o z(4IPU*n>`cw2V~HM#O`Z^bv|cK|K};buJ|#{reT8R)f+P2<3$0YGh!lqx3&a_wi2Q zN^U|U$w4NP!Z>5|O)>$GjS5wqL3T8jTn%Vfg3_KnyUM{M`?bm)9oqZP&1w1)o=@+(5eUF@=P~ zk2B5AKxQ96n-6lyjh&xD!gHCzD$}OOdKQQk7LXS-fk2uy#h{ktqDo{o&>O!6%B|)` zg?|JgcH{P*5SoE3(}QyGc=@hqlB5w;bnmF#pL4iH`TSuft$dE5j^qP2S)?)@pjRQZ zBfo6g>c!|bN-Y|(Wah2o61Vd|OtXS?1`Fu&mFZ^yzUd4lgu7V|MRdGj3e#V`=mnk- zZ@LHn?@dDi=I^}R?}mZwduik!hC%=Hcl56u{Wrk1|1SxlgnzG&e7Vzh*wNM(6Y!~m z`cm8Ygc1$@z9u9=m5vs1(XXvH;q16fxyX4&e5dP-{!Kd555FD6G^sOXHyaCLka|8j zKKW^E>}>URx736WWNf?U6Dbd37Va3wQkiE;5F!quSnVKnmaIRl)b5rM_ICu4txs+w zj}nsd0I_VG^<%DMR8Zf}vh}kk;heOQTbl ziEoE;9@FBIfR7OO9y4Pwyz02OeA$n)mESpj zdd=xPwA`nO06uGGsXr4n>Cjot7m^~2X~V4yH&- zv2llS{|und45}Pm1-_W@)a-`vFBpD~>eVP(-rVHIIA|HD@%7>k8JPI-O*<7X{L*Ik zh^K`aEN!BteiRaY82FVo6<^8_22=aDIa8P&2A3V<(BQ;;x8Zs-1WuLRWjQvKv1rd2 zt%+fZ!L|ISVKT?$3iCK#7whp|1ivz1rV*R>yc5dS3kIKy_0`)n*%bfNyw%e7Uo}Mnnf>QwDgeH$X5eg_)!pI4EJjh6?kkG2oc6Af0py z(txE}$ukD|Zn=c+R`Oq;m~CSY{ebu9?!is}01sOK_mB?{lSY33E=!KkKtMeI*FO2b z%95awv9;Z|UDp3xm+aP*5I!R-_M2;GxeCRx3ATS0iF<_Do2Mi)Hk2 zjBF35VB>(oamIYjunu?g0O-?LuOvtfs5F(iiIicbu$HMPPF%F>pE@hIRjzT)>aa=m zwe;H9&+2|S!m74!E3xfO{l3E_ab`Q^tZ4yH9=~o2DUEtEMDqG=&D*8!>?2uao%w`&)THr z^>=L3HJquY>6)>dW4pCWbzrIB+>rdr{s}}cL_?#!sOPztRwPm1B=!jP7lQG|Iy6rP zVqZDNA;xaUx&xUt?Ox|;`9?oz`C0#}mc<1Urs#vTW4wd{1_r`eX=BeSV z_9WV*9mz>PH6b^z{VYQJ1nSTSqOFHE9u>cY)m`Q>=w1NzUShxcHsAxasnF2BG;NQ; zqL1tjLjImz_`q=|bAOr_i5_NEijqYZ^;d5y3ZFj6kCYakJh**N_wbfH;ICXq?-p#r z{{ljNDPSytOaG#7=yPmA&5gyYI%^7pLnMOw-RK}#*dk=@usL;|4US?{@K%7esmc&n z5$D*+l&C9)Bo@$d;Nwipd!68&+NnOj^<~vRcKLX>e03E|;to;$ndgR;9~&S-ly5gf z{rzj+j-g$;O|u?;wwxrEpD=8iFzUHQfl{B>bLHqH(9P zI59SS2PEBE;{zJUlcmf(T4DrcO?XRWR}?fekN<($1&AJTRDyW+D*2(Gyi?Qx-i}gy z&BpIO!NeVdLReO!YgdUfnT}7?5Z#~t5rMWqG+$N2n%5o#Np6ccNly}#IZQsW4?|NV zR9hrcyP(l#A+U4XcQvT;4{#i)dU>HK>aS!k1<3s2LyAhm2(!Nu%vRC9T`_yn9D+r} z1i&U~IcQ?4xhZYyH6WL-f%}qIhZkc&}n2N0PM| z6|XA9d-y;!`D{p;xu*gv7a|zaZ*MiQ)}zPzW4GB0mr)}N-DmB&hl1&x`2@sxN572_ zS)RdJyR%<7kW0v3Q_|57JKy&9tUdbqz}|hwn84}U*0r^jt6Ssrp+#1y=JBcZ+F`f(N?O0XL1OFGN`1-r?S<#t4*C9|y~e)!UYZ zRQ3M8m%~M)VriIvn~XzoP;5qeu(ZI>Y#r zAd)J)G9)*BeE%gmm&M@Olg3DI_zokjh9NvdGbT z+u4(Y&uC6tBBefIg~e=J#8i1Zxr>RT)#rGaB2C71usdsT=}mm`<#WY^6V{L*J6v&l z1^Tkr6-+^PA)yC;s1O^3Q!)Reb=fxs)P~I*?i&j{Vbb(Juc?La;cA5(H7#FKIj0Or zgV0BO{DUs`I9HgQ{-!g@5P^Vr|C4}~w6b=#`Zx0XcVSd?(04HUHwK(gJNafgQNB9Z zCi3TgNXAeJ+x|X|b@27$RxuYYuNSUBqo#uyiH6H(b~K*#!@g__4i%HP5wb<+Q7GSb zTZjJw96htUaGZ89$K_iBo4xEOJ#DT#KRu9ozu!GH0cqR>hP$nk=KXM%Y!(%vWQ#}s zy=O#BZ>xjUejMH^F39Bf0}>D}yiAh^toa-ts#gt6Mk9h1D<9_mGMBhLT0Ce2O3d_U znaTkBaxd-8XgwSp5)x-pqX5=+{cSuk6kyl@k|5DQ!5zLUVV%1X9vjY0gerbuG6nwZu5KDMdq(&UMLZ zy?jW#F6joUtVyz`Y?-#Yc0=i*htOFwQ3`hk$8oq35D}0m$FAOp#UFTV3|U3F>@N?d zeXLZCZjRC($%?dz(41e~)CN10qjh^1CdAcY(<=GMGk@`b1ptA&L*{L@_M{%Vd5b*x#b1(qh=7((<_l%ZUaHtmgq} zjchBdiis{Afxf@3CjPR09E*2#X(`W#-n`~6PcbaL_(^3tfDLk?Nb6CkW9v!v#&pWJ3iV-9hz zngp#Q`w`r~2wt&cQ9#S7z0CA^>Mzm7fpt72g<0y-KT{G~l-@L#edmjZQ}7{*$mLgSdJfS$Ge{hrD=mr;GD)uYq8}xS zT>(w_;}894Kb}(P5~FOpFIEjadhmxD(PsZbKwa-qxVa7Oc7~ebPKMeN(pCRzq8s@l z`|l^*X1eK1+Spz--WkSW_nK`Cs@JmkY4+p=U91nJoy{tSH;TzuIyS)Q_(S@;Iakua zpuDo5W54Mo;jY@Ly1dY)j|+M%$FJ0`C=FW#%UvOd&?p}0QqL20Xt!#pr8ujy6CA-2 zFz6Ex5H1i)c9&HUNwG{8K%FRK7HL$RJwvGakleLLo}tsb>t_nBCIuABNo$G--_j!gV&t8L^4N6wC|aLC)l&w04CD6Vc#h^(YH@Zs4nwUGkhc_-yt{dK zMZ<%$swLmUl8`E~RLihGt@J5v;r;vT&*Q!Cx zZ55-zpb;W7_Q{tf$mQvF61(K>kwTq0x{#Din||)B{+6O#ArLi)kiHWVC4`fOT&B(h zw&YV`J1|^FLx~9Q%r-SFhYl4PywI7sF2Q$>4o50~dfp5nn}XHv-_DM?RGs#+4gM;% znU>k=81G~f6u%^Z{bcX&sUv*h|L+|mNq=W43y@{~C zpL-TW3hYPs0^*OqS#KQwA^CGG_A-6#`_{1LBCD&*3nY0UHWJj1D|VP%oQlFxLllaA zVI@2^)HZ%E*=RbQcFOKIP7?+|_xVK+2oG(t_EGl2y;Ovox zZb^qVpe!4^reKvpIBFzx;Ji=PmrV>uu-Hb>`s?k?YZQ?>av45>i(w0V!|n?AP|v5H zm`e&Tgli#lqGEt?=(?~fy<(%#nDU`O@}Vjib6^rfE2xn;qgU6{u36j_+Km%v*2RLnGpsvS+THbZ>p(B zgb{QvqE?~50pkLP^0(`~K& zjT=2Pt2nSnwmnDFi2>;*C|OM1dY|CAZ5R|%SAuU|5KkjRM!LW_)LC*A zf{f>XaD+;rl6Y>Umr>M8y>lF+=nSxZX_-Z7lkTXyuZ(O6?UHw^q; z&$Zsm4U~}KLWz8>_{p*WQ!OgxT1JC&B&>|+LE3Z2mFNTUho<0u?@r^d=2 z-av!n8r#5M|F%l;=D=S1mGLjgFsiYAOODAR}#e^a8 zfVt$k=_o}kt3PTz?EpLkt54dY}kyd$rU zVqc9SN>0c z753j-gdN~UiW*FUDMOpYEkVzP)}{Ds*3_)ZBi)4v26MQr140|QRqhFoP=a|;C{#KS zD^9b-9HM11W+cb1Y)HAuk<^GUUo(ut!5kILBzAe)Vaxwu4Up!7Ql*#DDu z>EB84&xSrh>0jT!*X81jJQq$CRHqNj29!V3FN9DCx)~bvZbLwSlo3l^zPb1sqBnp) zfZpo|amY^H*I==3#8D%x3>zh#_SBf?r2QrD(Y@El!wa;Ja6G9Y1947P*DC|{9~nO& z*vDnnU!8(cV%HevsraF%Y%2{Z>CL0?64eu9r^t#WjW4~3uw8d}WHzsV%oq-T)Y z0-c!FWX5j1{1##?{aTeCW2b$PEnwe;t`VPCm@sQ`+$$L2=3kBR%2XU1{_|__XJ$xt zibjY2QlDVs)RgHH*kl&+jn*JqquF)k_Ypibo00lcc<2RYqsi-G%}k0r(N97H7JEn7@E3ZTH0JK>d8)E~A-D z!B&z9zJw0Bi^fgQZI%LirYaBKnWBXgc`An*qvO^*$xymqKOp(+3}IsnVhu?YnN7qz zNJxDN-JWd7-vIiv2M9ih>x3gNVY%DzzY~dCnA}76IRl!`VM=6=TYQ=o&uuE8kHqZT zoUNod0v+s9D)7aLJ|hVqL0li1hg)%&MAciI(4YJ=%D4H$fGQ&Lu-?@>>@pEgC;ERrL= zI^cS&3q8fvEGTJZgZwL5j&jp%j9U^Of6pR{wA^u=tVt#yCQepXNIbynGnuWbsC_EE zRyMFq{5DK692-*kyGy~An>AdVR9u___fzmmJ4;^s0yAGgO^h{YFmqJ%ZJ_^0BgCET zE6(B*SzeZ4pAxear^B-YW<%BK->X&Cr`g9_;qH~pCle# zdY|UB5cS<}DFRMO;&czbmV(?vzikf)Ks`d$LL801@HTP5@r><}$xp}+Ip`u_AZ~!K zT}{+R9Wkj}DtC=4QIqJok5(~0Ll&_6PPVQ`hZ+2iX1H{YjI8axG_Bw#QJy`6T>1Nn z%u^l`>XJ{^vX`L0 z1%w-ie!dE|!SP<>#c%ma9)8K4gm=!inHn2U+GR+~ zqZVoa!#aS0SP(|**WfQSe?cA=1|Jwk`UDsny%_y{@AV??N>xWekf>_IZLUEK3{Ksi zWWW$if&Go~@Oz)`#=6t_bNtD$d9FMBN#&97+XKa+K2C@I9xWgTE{?Xnhc9_KKPcujj@NprM@e|KtV_SR+ zSpeJ!1FGJ=Te6={;;+;a46-*DW*FjTnBfeuzI_=I1yk8M(}IwEIGWV0Y~wia;}^dg z{BK#G7^J`SE10z4(_Me=kF&4ld*}wpNs91%2Ute>Om`byv9qgK4VfwPj$`axsiZ)wxS4k4KTLb-d~!7I@^Jq`>?TrixHk|9 zqCX7@sWcVfNP8N;(T>>PJgsklQ#GF>F;fz_Rogh3r!dy*0qMr#>hvSua;$d z3TCZ4tlkyWPTD<=5&*bUck~J;oaIzSQ0E03_2x{?weax^jL3o`ZP#uvK{Z5^%H4b6 z%Kbp6K?>{;8>BnQy64Jy$~DN?l(ufkcs6TpaO&i~dC>0fvi-I^7YT#h?m;TVG|nba%CKRG%}3P*wejg) zI(ow&(5X3HR_xk{jrnkA-hbwxEQh|$CET9Qv6UpM+-bY?E!XVorBvHoU59;q<9$hK z%w5K-SK zWT#1OX__$ceoq0cRt>9|)v}$7{PlfwN}%Wh3rwSl;%JD|k~@IBMd5}JD#TOvp=S57 zae=J#0%+oH`-Av}a(Jqhd4h5~eG5ASOD)DfuqujI6p!;xF_GFcc;hZ9k^a7c%%h(J zhY;n&SyJWxju<+r`;pmAAWJmHDs{)V-x7(0-;E?I9FWK@Z6G+?7Py8uLc2~Fh1^0K zzC*V#P88(6U$XBjLmnahi2C!a+|4a)5Ho5>owQw$jaBm<)H2fR=-B*AI8G@@P-8I8 zHios92Q6Nk-n0;;c|WV$Q);Hu4;+y%C@3alP`cJ2{z~*m-@de%OKVgiWp;4Q)qf9n zJ!vmx(C=_>{+??w{U^Bh|LFJ<6t}Er<-Tu{C{dv8eb(kVQ4!fOuopTo!^x1OrG}0D zR{A#SrmN`=7T29bzQ}bwX8OUufW9d9T4>WY2n15=k3_rfGOp6sK0oj7(0xGaEe+-C zVuWa;hS*MB{^$=0`bWF(h|{}?53{5Wf!1M%YxVw}io4u-G2AYN|FdmhI13HvnoK zNS2fStm=?8ZpKt}v1@Dmz0FD(9pu}N@aDG3BY8y`O*xFsSz9f+Y({hFx;P_h>ER_& z`~{z?_vCNS>agYZI?ry*V96_uh;|EFc0*-x*`$f4A$*==p`TUVG;YDO+I4{gJGrj^ zn?ud(B4BlQr;NN?vaz_7{&(D9mfd z8esj=a4tR-ybJjCMtqV8>zn`r{0g$hwoWRUI3}X5=dofN){;vNoftEwX>2t@nUJro z#%7rpie2eH1sRa9i6TbBA4hLE8SBK@blOs=ouBvk{zFCYn4xY;v3QSM%y6?_+FGDn z4A;m)W?JL!gw^*tRx$gqmBXk&VU=Nh$gYp+Swu!h!+e(26(6*3Q!(!MsrMiLri`S= zKItik^R9g!0q7y$lh+L4zBc-?Fsm8`CX1+f>4GK7^X2#*H|oK}reQnT{Mm|0ar<+S zRc_dM%M?a3bC2ILD`|;6vKA`a3*N~(cjw~Xy`zhuY2s{(7KLB{S>QtR3NBQ3>vd+= z#}Q)AJr7Y_-eV(sMN#x!uGX08oE*g=grB*|bBs}%^3!RVA4f%m3=1f0K=T^}iI&2K zuM2GG5_%+#v-&V>?x4W9wQ|jE2Q7Be8mOyJtZrqn#gXy-1fF1P$C8+We&B*-pi#q5 zETp%H6g+%#sH+L4=ww?-h;MRCd2J9zwQUe4gHAbCbH08gDJY;F6F)HtWCRW1fLR;)ysGZanlz*a+|V&@(ipWdB!tz=m_0 z6F}`d$r%33bw?G*azn*}Z;UMr{z4d9j~s`0*foZkUPwpJsGgoR0aF>&@DC;$A&(av z?b|oo;`_jd>_5nye`DVOcMLr-*Nw&nA z82E8Dw^$Lpso)gEMh?N|Uc^X*NIhg=U%enuzZOGi-xcZRUZmkmq~(cP{S|*+A6P;Q zprIkJkIl51@ng)8cR6QSXJtoa$AzT@*(zN3M+6`BTO~ZMo0`9$s;pg0HE3C;&;D@q zd^0zcpT+jC%&=cYJF+j&uzX87d(gP9&kB9|-zN=69ymQS9_K@h3ph&wD5_!4q@qI@ zBMbd`2JJ2%yNX?`3(u&+nUUJLZ=|{t7^Rpw#v-pqD2_3}UEz!QazhRty%|Q~WCo7$ z+sIugHA%Lmm{lBP#bnu_>G}Ja<*6YOvSC;89z67M%iG0dagOt1HDpDn$<&H0DWxMU zxOYaaks6%R@{`l~zlZ*~2}n53mn2|O&gE+j*^ypbrtBv{xd~G(NF?Z%F3>S6+qcry z?ZdF9R*a;3lqX_!rI(Cov8ER_mOqSn6g&ZU(I|DHo7Jj`GJ}mF;T(vax`2+B8)H_D zD0I;%I?*oGD616DsC#j0x*p+ZpBfd=9gR|TvB)832CRhsW_7g&WI@zp@r7dhg}{+4f=(cO2s+)jg0x(*6|^+6W_=YIfSH0lTcK* z%)LyaOL6em@*-_u)}Swe8rU)~#zT-vNiW(D*~?Zp3NWl1y#fo!3sK-5Ek6F$F5l3| zrFFD~WHz1}WHmzzZ!n&O8rTgfytJG*7iE~0`0;HGXgWTgx@2fD`oodipOM*MOWN-} zJY-^>VMEi8v23ZlOn0NXp{7!QV3F1FY_URZjRKMcY(2PV_ms}EIC^x z=EYB5UUQ{@R~$2Mwiw$_JAcF+szKB*n(`MYpDCl>~ss54uDQ%Xf-8|dgO zY)B_qju=IaShS|XsQo=nSYxV$_vQR@hd~;qW)TEfU|BA0&-JSwO}-a*T;^}l;MgLM zz}CjPlJX|W2vCzm3oHw3vqsRc3RY=2()}iw_k2#eKf&VEP7TQ;(DDzEAUgj!z_h2Br;Z3u=K~LqM6YOrlh)v9`!n|6M-s z?XvA~y<5?WJ{+yM~uPh7uVM&g-(;IC3>uA}ud?B3F zelSyc)Nx>(?F=H88O&_70%{ATsLVTAp88F-`+|egQ7C4rpIgOf;1tU1au+D3 zlz?k$jJtTOrl&B2%}D}8d=+$NINOZjY$lb{O<;oT<zXoAp01KYG$Y4*=)!&4g|FL(!54OhR-?)DXC&VS5E|1HGk8LY;)FRJqnz zb_rV2F7=BGwHgDK&4J3{%&IK~rQx<&Kea|qEre;%A~5YD6x`mo>mdR)l?Nd%T2(5U z_ciT02-zt_*C|vn?BYDuqSFrk3R(4B0M@CRFmG{5sovIq4%8AhjXA5UwRGo)MxZlI zI%vz`v8B+#ff*XtGnciczFG}l(I}{YuCco#2E6|+5WJ|>BSDfz0oT+F z%QI^ixD|^(AN`MS6J$ zXlKNTFhb>KDkJp*4*LaZ2WWA5YR~{`={F^hwXGG*rJYQA7kx|nwnC58!eogSIvy{F zm1C#9@$LhK^Tl>&iM0wsnbG7Y^MnQ=q))MgApj4)DQt!Q5S`h+5a%c7M!m%)?+h65 z0NHDiEM^`W+M4)=q^#sk(g!GTpB}edwIe>FJQ+jAbCo#b zXmtd3raGJNH8vnqMtjem<_)9`gU_-RF&ZK!aIenv7B2Y0rZhon=2yh&VsHzM|`y|0x$Zez$bUg5Nqj?@~^ zPN43MB}q0kF&^=#3C;2T*bDBTyO(+#nZnULkVy0JcGJ36or7yl1wt7HI_>V7>mdud zv2II9P61FyEXZuF$=69dn%Z6F;SOwyGL4D5mKfW)q4l$8yUhv7|>>h_-4T*_CwAyu7;DW}_H zo>N_7Gm6eed=UaiEp_7aZko@CC61@(E1be&5I9TUq%AOJW>s^9w%pR5g2{7HW9qyF zh+ZvX;5}PN0!B4q2FUy+C#w5J?0Tkd&S#~94(AP4%fRb^742pgH7Tb1))siXWXHUT z1Wn5CG&!mGtr#jq6(P#!ck@K+FNprcWP?^wA2>mHA03W?kj>5b|P0ErXS) zg2qDTjQ|grCgYhrH-RapWCvMq5vCaF?{R%*mu}1)UDll~6;}3Q*^QOfj!dlt02lSzK z?+P)02Rrq``NbU3j&s*;<%i4Y>y9NK&=&KsYwvEmf5jwTG6?+Pu1q9M8lLlx)uZZ7 zizhr~e0ktGs-=$li-2jz^_48-jk**y&5u0`B2gc#i$T1~t+AS*kEfR*b{^Ec>2-F~ zKYRl&uQ5yO@EtAZX8ZSqx;8+AKf+CqhlUSpp*VfyBMv+%wxN5GukZEi^_to%MFRc0 zdXqJ*jk?#uYT6EJe446@(f6G4vhnxQP|pGeJ?-#|Ksq?g*ky=}x+Qnx+!<>Y(XStN zQIND`{KU}&l)E*ntI^}kJ=ly8DML{!(58Xk4_bzIc@v~e;>wKl_`7G%pGz~4KH*CTp;_|52)d!+ximd$|8v@zzEq%j68QXkgf$7eM~xdM5q5i z{?qFx_W|eq@L03bWJfjy^z@()-iCjzjREuf zb_a(yTz)ZKWCF%Lp>^2-%Q?*t{06}x#DLN3cO=i>h6#-a`z;<5rBGGM6GA(WqvRcX%Pn?Uvs1#e|ePSNJEC%+X(YI$x)`s$%>O#%}D9dgqWfq4yfVz^%FglokdFR}uJQhx|}_w`9Ulx38Ha>ZslKs58c-@IFI&f;?xM zbK>rKNfPFsf>%+k6%(A6=7Aac^_qrOCNqb3ZVJ;8pt!?1DR*ynJb#@II9h?)xB)A~ zm9Kk)Hy}!Z+W}i6ZJDy+?yY_=#kWrzgV)2eZAx_E=}Nh7*#<&mQz`Umfe$+l^P(xd zN}PA2qII4}ddCU+PN+yxkH%y!Qe(;iH3W%bwM3NKbU_saBo<8x9fGNtTAc_SizU=o zC3n2;c%LoU^j90Sz>B_p--Fzqv7x7*?|~-x{haH8RP)p|^u$}S9pD-}5;88pu0J~9 zj}EC`Q^Fw}`^pvAs4qOIuxKvGN@DUdRQ8p-RXh=3S#<`3{+Qv6&nEm)uV|kRVnu6f zco{(rJaWw(T0PWim?kkj9pJ)ZsUk9)dSNLDHf`y&@wbd;_ita>6RXFJ+8XC*-wsiN z(HR|9IF283fn=DI#3Ze&#y3yS5;!yoIBAH(v}3p5_Zr+F99*%+)cp!Sy8e+lG?dOc zuEz<;3X9Z5kkpL_ZYQa`sioR_@_cG z8tT~GOSTWnO~#?$u)AcaBSaV7P~RT?Nn8(OSL1RmzPWRWQ$K2`6*)+&7^zZBeWzud z*xb3|Fc~|R9eH+lQ#4wF#c;)Gka6lL(63C;>(bZob!i8F-3EhYU3|6-JBC0*5`y0| zBs!Frs=s!Sy0qmQNgIH|F`6(SrD1js2prni_QbG9Sv@^Pu2szR9NZl8GU89gWWvVg z2^-b*t+F{Nt>v?js7hnlC`tRU(an0qQG7;h6T~ z-`vf#R-AE$pzk`M{gCaia}F`->O2)60AuGFAJg> z*O2IZqTx=AzDvC49?A92>bQLdb&32_4>0Bgp0ESXXnd4B)!$t$g{*FG%HYdt3b3a^J9#so%BJMyr2 z{y?rzW!>lr097b9(75#&4&@lkB1vT*w&0E>!dS+a|ZOu6t^zro2tiP)bhcNNxn zbJs3_Fz+?t;4bkd8GfDI7ccJ5zU`Bs~ zN~bci`c`a%DoCMel<-KUCBdZRmew`MbZEPYE|R#|*hhvhyhOL#9Yt7$g_)!X?fK^F z8UDz)(zpsvriJ5aro5>qy`Fnz%;IR$@Kg3Z3EE!fv9CAdrAym6QU82=_$_N5*({_1 z7!-=zy(R{xg9S519S6W{HpJZ8Is|kQ!0?`!vxDggmslD59)>iQ15f z7J8NqdR`9f8H|~iFGNsPV!N)(CC9JRmzL9S}7U-K@`X893f3f<8|8Ls!^eA^#(O6nA+ByFIXcz_WLbfeG|nHJ5_sJJ^gNJ%SI9#XEfNRbzV+!RkI zXS$MOVYb2!0vU}Gt7oUy*|WpF^*orBot~b2J@^be?Gq;U%#am8`PmH-UCFZ&uTJlnetYij0z{K1mmivk$bdPbLodu;-R@@#gAV!=d%(caz$E?r zURX0pqAn7UuF6dULnoF1dZ$WM)tHAM{eZK6DbU1J`V5Dw<;xk}Nl`h+nfMO_Rdv z3SyOMzAbYaD;mkxA7_I_DOs#Bk;e5D%gsS3q)hlmi1w{FsjKNJE22`AjmNiAPRnIc zcIkN25;rOn3FipAFd(PnlK9{03w6Q<(68#1Jw`{axEGQE{Ac>^U$h);h2ADICmaNxrfpb`Jdr*)Y1SicpYKCFv$3vf~;5aW>n^7QGa63MJ z;B1+Z>WQ615R2D8JmmT`T{QcgZ+Kz1hTu{9FOL}Q8+iFx-Vyi}ZVVcGjTe>QfA`7W zFoS__+;E_rQIQxd(Bq4$egKeKsk#-9=&A!)(|hBvydsr5ts0Zjp*%*C0lM2sIOx1s zg$xz?Fh?x!P^!vWa|}^+SY8oZHub7f;E!S&Q;F?dZmvBxuFEISC}$^B_x*N-xRRJh zn4W*ThEWaPD*$KBr8_?}XRhHY7h^U1aN6>m=n~?YJQd8+!Uyq_3^)~4>XjelM&!c9 zCo|0KsGq7!KsZ~9@%G?i>LaU7#uSTMpypocm*oqJHR|wOgVWc7_8PVuuw>x{kEG4T z$p^DV`}jUK39zqFc(d5;N+M!Zd3zhZN&?Ww(<@AV-&f!v$uV>%z+dg9((35o@4rqLvTC-se@hkn^6k7+xHiK-vTRvM8{bCejbU;1@U=*r}GTI?Oc$!b6NRcj83-zF; z=TB#ESDB`F`jf4)z=OS76Se}tQDDHh{VKJk#Ad6FDB_=afpK#pyRkGrk~OuzmQG)} z*$t!nZu$KN&B;|O-aD=H<|n6aGGJZ=K9QFLG0y=Jye_ElJFNZJT;fU8P8CZcLBERjioAOC0Vz_pIXIc};)8HjfPwNy zE!g|lkRv3qpmU?shz(BBt5%TbpJC3HzP9!t7k*Fh48!-HlJ4TTgdCr3rCU!iF}kgu z4Qs;K@XOY~4f~N}Jl8V_mGbwzvNLbl&0e9UG4W;kvjTK|5`-Ld+eQ6YRF`N0ct%u% z^3J_{7r#_W1zm|>IPN!yWCRrN)N!7v`~ptNkIXKipQ6ogFvcnI5ugxdoa{d;uD67g zgo^}QuZRkB540Vc!@c80(wFG=$ct}oHq(#W0+-XX(;Rrt`x=<45X}ficNtI2(&}=~ zb(!}tNz?s`wm{gK?2tdf+OEF;tzx<(3fMd7_tM@Ghs$Z(Os-H(kYq#qB|J-aC9Ku?fsWwJhB36c)A zu|a7ZF?V8X7l2g5~xqZf>2=6Dsi5lfo zKIRL&@MLJyaBE)V_9=pJYu%U2wxR*-(0MI5_|yqP`?h@cks(5LR@XUKLMI_xuVtiu zRvpDS8MyUMRFM6`P+Sjc!A_e^H38Qu7b{b7QZ>NHyA6k-YYygQuW&C_OGO(7V7?}r)zedSVpBI zuk29Z4GW3C0GpfozbZQya454sjt@ndQmsp=DA&@sWw&xmOlDk1JIcMNp~-ES$&A~k zG#W(6hBj?!Fu8Q4WYexoSBa8_5=v20xnx6H?e;$t)5|f&{7=vOye^&3_c-Ug?|a@e z=X`&qT_5B7N9vZoPBhXOTEDV;4&x2Je4}T(UB~O-$D#CjX77$R?RZ*`ed~$G;$4YS z4n*|Pop(!NN79Hk2}U#cfEEwdxM)xQm}$~rV03xc=#U@@Y*}qEmot5KvDb=8{!E-n zl4p?}&g2h^sUGyTcGh=0aQzQb*k;K;dvbeZUgmwEv>%#(EPtj=gHKdi|E8@w+|>KC zxEU>b>P+9Xf}pEyQK(}#QrBG4Jaf!iE!qpMbTu>gb!gtdq<`@xO+roQl+S_7)!G(% zdy)$iGmJ1cwP?F=IyyV1-$|kf|EKM3B@I&lZ%NI@VV;*mQdLWjc#t|Vbk_Q~>&O03 zIcSr$(qLAINj7a z;!||v&1D5SX#X@5jNd}jUsi-CH_Scjyht&}q2p*CJCC-`&NyXf)vD5{e!HO629D-O z%bZelTcq=DoRX>zeWCa^RmR3*{x9;3lZ75M#S)!W0bRIFH#P6b%{|HRSZ5!!I#s)W z_|XXZQ<0_`>b^^0Z>LU64Yg1w)8}#M^9se(OZ9~baZ7fsKFc;EtnB>kesci#>=icG zuHdjax2^=!_(9?0l7;G7^-}9>Y#M zm;9*GT~dBuYWdk49%mZM0=H#FY1)}7NE5DE_vsqrA0`?0R0q535qHjWXcl|gz9Fq$ zMKxgL;68l!gm3y0durIr3LHv~y*ABm` zYhQG0UW#hg@*A{&G!;$FS43}rIF$e6yRdGJWVR<}uuJ_5_8qa3xaHH^!VzUteVp;> z<0`M>3tnY$ZFb$(`0sg93TwGyP;`9UYUWxO&CvAnSzei&ap))NcW;R`tA=y^?mBmG+M*&bqW5kL$V(O;(p)aEk`^ci?2Jwxu>0sy>a7+Wa9t z5#I2o;+gr^9^&km^z7>xJWbN&Ft>Vna34E zI@BBzwX)R}K3SL?)enrDJ45QLt;-7CFJk{`cF3L4Z^CtG_r5)0)HV>BOYPIUh#D%| zYQAu31f{bm-D*`_k7DTTr?Nkw_gY%J1cb2&TdtibY?V=|SSIOlA;|5C!2@?YQ z-$?G0jj^mG|MP>DmbF7}T~C$H6=CpZ~hd zZ1C|xV@=h#^~`3LSCnmI(vZ|5r3>eq5*UB)dhdy``*gKY3Eg%jSK8I-`G+OWWlD)T zt$wSQ=||lSkiKy}YF-k}@W9EiS?)z`hK{R!dd-$BCJvBtAN-yXn3njU$MisEtp!?Q z%Vk-*(wy9dd15(-WFw_&^tT;;IpF?ox1`Qq3-0zVTk+$W_?q}GfAQlPcrB^?&tWSI z2BB!K=sH7FUYmXa_dcV^Z3>5z8}~W{S!$jVR_3hu_|wl2|gmRH8ftn^z@fW75*;-`;wU+fY+BR_yx6BZnE5_Hna({jrPiubRp$jZ=T=t$hx&NeCV1!vuCcl4PJ0p0Fjp>6K} zHkoD1gQk=P2hYcT%)cJ2Q5WuA|5_x+dX0%hnozfTF>$#Wz~X!MY>){H4#fB#7^ID* z1*o2Hzp}?WVs&gbS?Uq(CT0sP+F)u9{xfgg6o_{8J#m;|NeJqDHhb(Q8%z8aM_qeM zn83>d`uDd47WIuKp78JBYo2SYupGcNXIzeou^eMY`@%Bv8elZ>q~3uq#~IX)g%g;h zoUXymEd>|kVsMkyb&1l~lrE-`w(0PObapYa35DJ4Y03Jv_!DKp}0HTbOgZRM=;PSsuAJJJ1 zItc+tu9;ANG;qHaCI|T85!euhFK~VK^G2LZV1+cbzS?>ar@>emg;JTI5VAn1g5U~| zU=p&k0OlSzc$U=s#9_uL3&n|6A1X$XvrE9vFV@`A4G#!D1QcFCeE`F2N(deJx>)*A z$XIW0P~-NbAd=5i6`s<~(vAQX9t$dbVqc5|E|CHRtb$1(l&KSNh_t2#k_l95KnP86 z)ns_DGspv-M0z0#h2a+*oH|{5~j{ zXGD=}cLrBSESQ0u$XmQlFfWMCAWaS;wKK%#aSSYK=qljBiY(s zT$v;We24&$w=avIILsMt0%1fDyah|AlLNg#WL$Lu)tf}YfqO%+pH~QC*bZO4aM*i9 zrPFf|5!hv@XY8CzaFh*Dy9vH|2fKKr(@x}`L#9^*vOae|lk`adG#oZZAyk|TOV8`9L zc-sQu%y1MQes&J?)a1}Zc*>-P!6j-T#75V$lLC!TuMB(!G-+D2;XptUxymSPFI-K&0x}B1?h$ z3-9**-9!);fwyiWB5gS$i;P~c=^}5-6G@{4TWDBRDc6(M|%qa-mS`z`u9kWo{Xl_uc;hXOkRd 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] ... --- 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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/290] 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 fcd567808fe691676b871427184c5fa1be1e87da Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 16 Jul 2022 00:12:57 -0400 Subject: [PATCH 095/290] This was supposed to be a debug log --- .../org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 2ebce7acd..21c54308d 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -176,7 +176,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); } } - geyserLogger.info("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); + geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); From 192ea1a0fca05b52547dec45ebc7484bb86a67f1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 16 Jul 2022 13:11:31 -0400 Subject: [PATCH 096/290] Update Geyser-Fabric build propagation (#3145) --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index ac10b06dd..1a98f47ad 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -94,7 +94,7 @@ pipeline { success { script { if (env.BRANCH_NAME == 'master') { - build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.18', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] + build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] build propagate: false, wait: false, job: 'GeyserMC/GeyserConnect/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] } } From 3de2b33e30136e2ac77877f3dfadb297524c6585 Mon Sep 17 00:00:00 2001 From: David Choo Date: Sun, 17 Jul 2022 21:00:08 -0400 Subject: [PATCH 097/290] Armor stand fixes (#3147) Co-authored-by: David Choo Co-authored-by: The Judge <53906078+thejudge156@users.noreply.github.com> --- .../entity/type/living/ArmorStandEntity.java | 181 +++++++++--------- .../org/geysermc/geyser/util/EntityUtils.java | 7 +- 2 files changed, 88 insertions(+), 100 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index 75b2ad991..c368deb6d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -26,13 +26,13 @@ package org.geysermc.geyser.entity.type.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; import lombok.Getter; import net.kyori.adventure.text.Component; import org.geysermc.geyser.entity.EntityDefinition; @@ -54,6 +54,8 @@ public class ArmorStandEntity extends LivingEntity { @Getter private boolean isSmall = false; + private boolean isNameTagVisible = false; + /** * On Java Edition, armor stands always show their name. Invisibility hides the name on Bedrock. * By having a second entity, we can allow an invisible entity with the name tag. @@ -75,7 +77,6 @@ public class ArmorStandEntity extends LivingEntity { * - No armor, no name: false * - No armor, yes name: true */ - @Getter private boolean positionRequiresOffset = false; /** * Whether we should update the position of this armor stand after metadata updates. @@ -88,7 +89,11 @@ public class ArmorStandEntity extends LivingEntity { @Override public void spawnEntity() { + Vector3f javaPosition = position; + // Apply the offset if we're the second entity + position = position.up(getYOffset()); super.spawnEntity(); + position = javaPosition; } @Override @@ -101,22 +106,18 @@ public class ArmorStandEntity extends LivingEntity { @Override public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) { - if (secondEntity != null) { - secondEntity.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround); - } - super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround); + moveAbsolute(position.add(relX, relY, relZ), yaw, pitch, headYaw, onGround, false); } @Override public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { if (secondEntity != null) { - secondEntity.moveAbsolute(applyOffsetToPosition(position), yaw, pitch, headYaw, isOnGround, teleported); - } else if (positionRequiresOffset) { - // Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands - position = applyOffsetToPosition(position); + secondEntity.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported); } - - super.moveAbsolute(position, yaw, yaw, yaw, isOnGround, teleported); + // Fake the height to be above where it is so the nametag appears in the right location + float yOffset = getYOffset(); + super.moveAbsolute(yOffset != 0 ? position.up(yOffset) : position , yaw, yaw, yaw, isOnGround, teleported); + this.position = position; } @Override @@ -127,20 +128,14 @@ public class ArmorStandEntity extends LivingEntity { public void setArmorStandFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); - + boolean offsetChanged = false; // isSmall boolean newIsSmall = (xd & 0x01) == 0x01; if (newIsSmall != isSmall) { - if (positionRequiresOffset) { - // Fix new inconsistency with offset - this.position = fixOffsetForSize(position, newIsSmall); - positionUpdateRequired = true; - } - isSmall = newIsSmall; - if (!isMarker && !isInvisible) { // Addition for isInvisible check caused by https://github.com/GeyserMC/Geyser/issues/2780 - toggleSmallStatus(); - } + offsetChanged = true; + // Update the passenger offset as the armor stand's height has changed + updatePassengerOffsets(); } // setMarker @@ -150,12 +145,21 @@ public class ArmorStandEntity extends LivingEntity { if (isMarker) { setBoundingBoxWidth(0.0f); setBoundingBoxHeight(0.0f); - dirtyMetadata.put(EntityData.SCALE, 0f); } else { - toggleSmallStatus(); + setBoundingBoxWidth(definition.width()); + setBoundingBoxHeight(definition.height()); } updateMountOffset(); + offsetChanged = true; + } + + if (offsetChanged) { + if (positionRequiresOffset) { + positionUpdateRequired = true; + } else if (secondEntity != null) { + secondEntity.positionUpdateRequired = true; + } updateSecondEntityStatus(false); } @@ -226,7 +230,7 @@ public class ArmorStandEntity extends LivingEntity { super.updateBedrockMetadata(); if (positionUpdateRequired) { positionUpdateRequired = false; - updatePosition(); + moveAbsolute(position, yaw, pitch, headYaw, onGround, true); } } @@ -285,6 +289,13 @@ public class ArmorStandEntity extends LivingEntity { updateSecondEntityStatus(true); } + @Override + public void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) { + super.setDisplayNameVisible(entityMetadata); + isNameTagVisible = entityMetadata.getPrimitiveValue(); + updateSecondEntityStatus(false); + } + /** * Determine if we need to load or unload the second entity. * @@ -293,40 +304,44 @@ public class ArmorStandEntity extends LivingEntity { private void updateSecondEntityStatus(boolean sendMetadata) { // A secondary entity always has to have the offset applied, so it remains invisible and the nametag shows. if (!primaryEntity) return; - if (!isInvisible || isMarker) { - // It is either impossible to show armor, or the armor stand isn't invisible. We good. + if (!isInvisible) { + // The armor stand isn't invisible. We good. setFlag(EntityFlag.INVISIBLE, false); + dirtyMetadata.put(EntityData.SCALE, getScale()); updateOffsetRequirement(false); - if (positionUpdateRequired) { - positionUpdateRequired = false; - updatePosition(); - } if (secondEntity != null) { secondEntity.despawnEntity(); secondEntity = null; } + if (sendMetadata) { + this.updateBedrockMetadata(); + } return; } boolean isNametagEmpty = nametag.isEmpty(); if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR) || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) { - // If the second entity exists, no need to recreate it. - // We can't stuff this check above or else it'll fall into another else case and delete the second entity - if (secondEntity != null) return; + // Reset scale of the proper armor stand + this.dirtyMetadata.put(EntityData.SCALE, getScale()); + // Set the proper armor stand to invisible to show armor + setFlag(EntityFlag.INVISIBLE, true); + // Update the position of the armor stand + updateOffsetRequirement(false); - // Create the second entity. It doesn't need to worry about the items, but it does need to worry about - // the metadata as it will hold the name tag. - secondEntity = new ArmorStandEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), null, - EntityDefinitions.ARMOR_STAND, position, motion, getYaw(), getPitch(), getHeadYaw()); - secondEntity.primaryEntity = false; - if (!this.positionRequiresOffset) { - // Ensure the offset is applied for the 0 scale - secondEntity.position = secondEntity.applyOffsetToPosition(secondEntity.position); + if (secondEntity == null) { + // Create the second entity. It doesn't need to worry about the items, but it does need to worry about + // the metadata as it will hold the name tag. + secondEntity = new ArmorStandEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), null, + EntityDefinitions.ARMOR_STAND, position, motion, getYaw(), getPitch(), getHeadYaw()); + secondEntity.primaryEntity = false; } // Copy metadata secondEntity.isSmall = isSmall; - //secondEntity.getDirtyMetadata().putAll(dirtyMetadata); //TODO check + secondEntity.isMarker = isMarker; + secondEntity.positionRequiresOffset = true; // Offset should always be applied + secondEntity.getDirtyMetadata().put(EntityData.NAMETAG, nametag); + secondEntity.getDirtyMetadata().put(EntityData.NAMETAG_ALWAYS_SHOW, isNameTagVisible ? (byte) 1 : (byte) 0); secondEntity.flags.merge(this.flags); // Guarantee this copy is NOT invisible secondEntity.setFlag(EntityFlag.INVISIBLE, false); @@ -335,18 +350,13 @@ public class ArmorStandEntity extends LivingEntity { // No bounding box as we don't want to interact with this entity secondEntity.getDirtyMetadata().put(EntityData.BOUNDING_BOX_WIDTH, 0.0f); secondEntity.getDirtyMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f); - secondEntity.spawnEntity(); - - // Reset scale of the proper armor stand - this.dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f); - // Set the proper armor stand to invisible to show armor - setFlag(EntityFlag.INVISIBLE, true); - // Update the position of the armor stand - updateOffsetRequirement(false); + if (!secondEntity.valid) { // Spawn the entity once + secondEntity.spawnEntity(); + } } else if (isNametagEmpty) { // We can just make an invisible entity // Reset scale of the proper armor stand - dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f); + dirtyMetadata.put(EntityData.SCALE, getScale()); // Set the proper armor stand to invisible to show armor setFlag(EntityFlag.INVISIBLE, true); // Update offset @@ -362,7 +372,7 @@ public class ArmorStandEntity extends LivingEntity { setFlag(EntityFlag.INVISIBLE, false); dirtyMetadata.put(EntityData.SCALE, 0.0f); // As the above is applied, we need an offset - updateOffsetRequirement(true); + updateOffsetRequirement(!isMarker); if (secondEntity != null) { secondEntity.despawnEntity(); @@ -374,35 +384,34 @@ public class ArmorStandEntity extends LivingEntity { } } - /** - * If this armor stand is not a marker, set its bounding box size and scale. - */ - private void toggleSmallStatus() { - setBoundingBoxWidth(isSmall ? 0.25f : definition.width()); - setBoundingBoxHeight(isSmall ? 0.9875f : definition.height()); - dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f); + @Override + public float getBoundingBoxWidth() { + // For consistency with getBoundingBoxHeight() + return super.getBoundingBoxWidth() * getScale(); + } + + @Override + public float getBoundingBoxHeight() { + // This is required so that EntityUtils#updateMountOffset() calculates the correct offset for small + // armor stands. The bounding box height is not changed as the SCALE entity data handles that for us. + return super.getBoundingBoxHeight() * getScale(); } /** - * @return the selected position with the position offset applied. + * @return the y offset required to position the name tag correctly */ - private Vector3f applyOffsetToPosition(Vector3f position) { - return position.add(0d, definition.height() * (isSmall ? 0.55d : 1d), 0d); + public float getYOffset() { + if (!positionRequiresOffset || isMarker || secondEntity != null) { + return 0; + } + return definition.height() * getScale(); } /** - * @return an adjusted offset for the new small status. + * @return the scale according to Java */ - private Vector3f fixOffsetForSize(Vector3f position, boolean isNowSmall) { - position = removeOffsetFromPosition(position); - return position.add(0d, definition.height() * (isNowSmall ? 0.55d : 1d), 0d); - } - - /** - * @return the selected position with the position offset removed. - */ - private Vector3f removeOffsetFromPosition(Vector3f position) { - return position.sub(0d, definition.height() * (isSmall ? 0.55d : 1d), 0d); + private float getScale() { + return isSmall ? 0.5f : 1f; } /** @@ -411,30 +420,12 @@ public class ArmorStandEntity extends LivingEntity { private void updateOffsetRequirement(boolean newValue) { if (newValue != positionRequiresOffset) { this.positionRequiresOffset = newValue; - if (positionRequiresOffset) { - this.position = applyOffsetToPosition(position); - // Update the passenger offset as armorstand is moving up by roughly 2 blocks - updatePassengerOffsets(); - } else { - this.position = removeOffsetFromPosition(position); - } - positionUpdateRequired = true; + this.positionUpdateRequired = true; + // Update the passenger offset as the armor stand's y offset has changed + updatePassengerOffsets(); } } - /** - * Updates position without calling movement code. - */ - private void updatePosition() { - MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); - moveEntityPacket.setRuntimeEntityId(geyserId); - moveEntityPacket.setPosition(position); - moveEntityPacket.setRotation(getBedrockRotation()); - moveEntityPacket.setOnGround(isOnGround()); - moveEntityPacket.setTeleported(false); - session.sendUpstreamPacket(moveEntityPacket); - } - @Override public Vector3f getBedrockRotation() { return Vector3f.from(getYaw(), getYaw(), getYaw()); diff --git a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java index d128989a8..8f92eaf3f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -190,11 +190,8 @@ public final class EntityUtils { if (passenger.getDefinition().entityType() == EntityType.FALLING_BLOCK) { yOffset += 0.5f; } - if (mount.getDefinition().entityType() == EntityType.ARMOR_STAND) { - ArmorStandEntity armorStand = (ArmorStandEntity) mount; - if (armorStand.isPositionRequiresOffset()) { - yOffset -= EntityDefinitions.ARMOR_STAND.height() * (armorStand.isSmall() ? 0.55d : 1d); - } + if (mount instanceof ArmorStandEntity armorStand) { + yOffset -= armorStand.getYOffset(); } Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset); passenger.setRiderSeatPosition(offset); From 467286060c3074e0ee237246a40eb3d308cc0ba9 Mon Sep 17 00:00:00 2001 From: sctigercat1 Date: Tue, 19 Jul 2022 21:23:04 -0400 Subject: [PATCH 098/290] Update items to 1.19.10 (#3151) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../populator/ItemRegistryPopulator.java | 8 +- .../bedrock/creative_items.1_19_10.json | 5440 +++++++++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 7694 -> 7762 bytes .../bedrock/runtime_item_states.1_19_10.json | 4530 ++++++++++++++ core/src/main/resources/mappings | 2 +- 5 files changed, 9976 insertions(+), 4 deletions(-) create mode 100644 core/src/main/resources/bedrock/creative_items.1_19_10.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_10.json diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index eaeefbe56..5dc60b44b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -36,6 +36,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; +import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -64,7 +65,9 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.V527_CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.V527_CODEC.getProtocolVersion(), + Collections.singletonMap("minecraft:trader_llama_spawn_egg", "minecraft:llama_spawn_egg"))); + paletteVersions.put("1_19_10", new PaletteVersion(Bedrock_v534.V534_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -210,8 +213,7 @@ public class ItemRegistryPopulator { Set javaOnlyItems = new ObjectOpenHashSet<>(); Collections.addAll(javaOnlyItems, "minecraft:spectral_arrow", "minecraft:debug_stick", - "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:trader_llama_spawn_egg", - "minecraft:bundle"); + "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:bundle"); if (!usingFurnaceMinecart) { javaOnlyItems.add("minecraft:furnace_minecart"); } diff --git a/core/src/main/resources/bedrock/creative_items.1_19_10.json b/core/src/main/resources/bedrock/creative_items.1_19_10.json new file mode 100644 index 000000000..50e09d830 --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_19_10.json @@ -0,0 +1,5440 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6071 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6072 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6073 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6074 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6075 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6076 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 947 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 4850 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 920 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1182 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1183 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1184 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1185 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1186 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1187 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1194 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1189 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1190 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1188 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1191 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1195 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1192 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1193 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 3930 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 6724 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 971 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 8082 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 5071 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 7817 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 429 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 730 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7364 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7365 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7366 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7367 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7368 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7369 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 6633 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 4290 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 7996 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 5853 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6584 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 3777 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5365 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 7586 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 4173 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 4625 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 4661 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 5399 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 633 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 3708 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 4092 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 273 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 128 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 7003 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 6967 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 6200 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 5063 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 4595 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 931 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5883 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 3587 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 3627 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 5350 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 5546 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 3537 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 4150 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4391 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6714 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 5308 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 7028 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 6530 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 106 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6602 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 6382 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 4767 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 7700 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 7755 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 7263 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 7430 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 206 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 3718 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 4297 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 4477 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 4604 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4587 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 4305 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 351 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 393 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 3902 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 6167 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 5840 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4653 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 294 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 7422 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 5522 + }, + { + "id" : "minecraft:wooden_door" + }, + { + "id" : "minecraft:spruce_door" + }, + { + "id" : "minecraft:birch_door" + }, + { + "id" : "minecraft:jungle_door" + }, + { + "id" : "minecraft:acacia_door" + }, + { + "id" : "minecraft:dark_oak_door" + }, + { + "id" : "minecraft:mangrove_door" + }, + { + "id" : "minecraft:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 229 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 6552 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 6650 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 5381 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 5589 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 7502 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 4485 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 321 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 4333 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 4733 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 4801 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 6164 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1133 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1141 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1140 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1148 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1145 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1147 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1134 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1137 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1138 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1146 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1142 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1136 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1144 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1143 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1135 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1139 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 5975 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 5233 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4852 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4860 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4859 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4867 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4864 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4866 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4853 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4856 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4857 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4861 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4855 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4862 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4854 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4858 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 8262 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 3571 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4270 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5822 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4273 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5793 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5270 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5271 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5272 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5273 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5274 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5275 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1149 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4275 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5820 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4271 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5823 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5794 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5788 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5824 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5805 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5810 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5808 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5809 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5807 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5806 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4274 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5804 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5821 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5789 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5790 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5791 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5792 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 5900 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 6484 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 910 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6018 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 4192 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 6600 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 6053 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5282 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7815 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 249 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 6545 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 708 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 7310 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4291 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 3716 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 3910 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 4765 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 7249 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 4552 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6547 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6548 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6549 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 281 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6087 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 4680 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 7214 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4586 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 5062 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4581 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 4160 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 5464 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 5364 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 5234 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 3615 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 6670 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 4582 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3653 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3654 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6580 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6581 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6582 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6583 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 5398 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 7979 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 291 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 8261 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 4651 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 593 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 8246 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 3553 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7734 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 694 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 707 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7542 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 4689 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 6166 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7197 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5478 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7293 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 3809 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 4851 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1159 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 272 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 4286 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 8260 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 5269 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 361 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3696 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3697 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6085 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6086 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 4233 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 892 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 4476 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 695 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 4234 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 7272 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 146 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 3775 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 8259 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3458 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3466 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3465 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3473 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3470 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3472 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3459 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3462 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3463 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3471 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3467 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3461 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3469 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3468 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3460 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3464 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 949 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 957 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 956 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 964 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 961 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 963 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 950 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 953 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 954 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 962 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 958 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 952 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 960 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 959 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 951 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 955 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6264 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6272 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6271 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6279 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6276 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6278 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6265 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6268 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6269 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6277 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6273 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6267 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6275 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6274 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6266 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6270 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 660 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 668 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 667 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 675 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 672 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 674 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 661 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 664 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 665 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 673 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 669 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 663 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 671 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 670 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 662 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 666 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 7124 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 641 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6176 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6184 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6183 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6191 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6188 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6190 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6177 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6180 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6185 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6187 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6186 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6178 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6182 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 5573 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 3531 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 8253 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 5834 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 3547 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 4167 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 1151 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 913 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 223 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 6610 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 5358 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 5471 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 5465 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 7011 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 965 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 6539 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7714 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 283 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 6889 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 4293 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 5905 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 5061 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 4189 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 6349 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 4349 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 24 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 1157 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 5830 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5751 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5752 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 3912 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 6975 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 8081 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 4650 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 6684 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 653 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 4690 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 912 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 4361 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 7699 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 4289 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 4287 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 3554 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 7347 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 4501 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 27 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 6107 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 7273 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 6106 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 8038 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 7262 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 6616 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 6350 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 7196 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 105 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 8287 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 654 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 656 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 658 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 7585 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 253 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 655 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 657 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 659 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 3682 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 7754 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4195 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4196 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 6986 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6672 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 7543 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6673 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 6288 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6674 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 5972 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6675 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 642 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3830 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 5848 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3831 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 216 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 348 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 8284 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 5897 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 6948 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 6486 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 7400 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3474 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3480 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3475 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3481 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3476 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3482 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3477 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3483 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3478 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3484 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3479 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3485 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 4161 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 4229 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 4294 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 6499 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 5902 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 5579 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6090 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6091 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6092 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6093 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4353 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4354 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 6666 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 7710 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 6339 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 712 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 713 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 714 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 715 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 716 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 717 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 6976 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 5754 + }, + { + "id" : "minecraft:wheat_seeds" + }, + { + "id" : "minecraft:pumpkin_seeds" + }, + { + "id" : "minecraft:melon_seeds" + }, + { + "id" : "minecraft:beetroot_seeds" + }, + { + "id" : "minecraft:wheat" + }, + { + "id" : "minecraft:beetroot" + }, + { + "id" : "minecraft:potato" + }, + { + "id" : "minecraft:poisonous_potato" + }, + { + "id" : "minecraft:carrot" + }, + { + "id" : "minecraft:golden_carrot" + }, + { + "id" : "minecraft:apple" + }, + { + "id" : "minecraft:golden_apple" + }, + { + "id" : "minecraft:enchanted_golden_apple" + }, + { + "id" : "minecraft:melon_block", + "blockRuntimeId" : 392 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 4577 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 7378 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 6685 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 929 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5455 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 928 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5454 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6492 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6490 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6491 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6489 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6493 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6497 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6495 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6496 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6494 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6498 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4616 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4614 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4615 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4613 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4617 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 69 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 67 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 68 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 66 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 70 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 246 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 7573 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 4362 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 302 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3616 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3617 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3618 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3619 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3620 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3621 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3622 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3623 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3624 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3625 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3626 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5452 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5453 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5456 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5457 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 6165 + }, + { + "id" : "minecraft:white_dye" + }, + { + "id" : "minecraft:light_gray_dye" + }, + { + "id" : "minecraft:gray_dye" + }, + { + "id" : "minecraft:black_dye" + }, + { + "id" : "minecraft:brown_dye" + }, + { + "id" : "minecraft:red_dye" + }, + { + "id" : "minecraft:orange_dye" + }, + { + "id" : "minecraft:yellow_dye" + }, + { + "id" : "minecraft:lime_dye" + }, + { + "id" : "minecraft:green_dye" + }, + { + "id" : "minecraft:cyan_dye" + }, + { + "id" : "minecraft:light_blue_dye" + }, + { + "id" : "minecraft:blue_dye" + }, + { + "id" : "minecraft:purple_dye" + }, + { + "id" : "minecraft:magenta_dye" + }, + { + "id" : "minecraft:pink_dye" + }, + { + "id" : "minecraft:ink_sac" + }, + { + "id" : "minecraft:glow_ink_sac" + }, + { + "id" : "minecraft:cocoa_beans" + }, + { + "id" : "minecraft:lapis_lazuli" + }, + { + "id" : "minecraft:bone_meal" + }, + { + "id" : "minecraft:vine", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 5479 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 5691 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 1158 + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 4677 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 3684 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 4194 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 6689 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 282 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 7027 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 155 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 7416 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 893 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 286 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 6538 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 5397 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 205 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 6175 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 345 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 5980 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 4320 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 7312 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 6888 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 5477 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 5684 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 290 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 7002 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 7810 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 4728 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 4376 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 304 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 347 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 215 + }, + { + "id" : "minecraft:chicken" + }, + { + "id" : "minecraft:porkchop" + }, + { + "id" : "minecraft:beef" + }, + { + "id" : "minecraft:mutton" + }, + { + "id" : "minecraft:rabbit" + }, + { + "id" : "minecraft:cod" + }, + { + "id" : "minecraft:salmon" + }, + { + "id" : "minecraft:tropical_fish" + }, + { + "id" : "minecraft:pufferfish" + }, + { + "id" : "minecraft:brown_mushroom", + "blockRuntimeId" : 3546 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 4585 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 7753 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 287 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7362 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 3611 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7363 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7348 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 6713 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 401 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4144 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4145 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4146 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4147 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4148 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4149 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 4641 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 7271 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 7997 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 4399 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 6435 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 6481 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 3510 + }, + { + "id" : "minecraft:chicken_spawn_egg" + }, + { + "id" : "minecraft:bee_spawn_egg" + }, + { + "id" : "minecraft:cow_spawn_egg" + }, + { + "id" : "minecraft:pig_spawn_egg" + }, + { + "id" : "minecraft:sheep_spawn_egg" + }, + { + "id" : "minecraft:wolf_spawn_egg" + }, + { + "id" : "minecraft:polar_bear_spawn_egg" + }, + { + "id" : "minecraft:ocelot_spawn_egg" + }, + { + "id" : "minecraft:cat_spawn_egg" + }, + { + "id" : "minecraft:mooshroom_spawn_egg" + }, + { + "id" : "minecraft:bat_spawn_egg" + }, + { + "id" : "minecraft:parrot_spawn_egg" + }, + { + "id" : "minecraft:rabbit_spawn_egg" + }, + { + "id" : "minecraft:llama_spawn_egg" + }, + { + "id" : "minecraft:horse_spawn_egg" + }, + { + "id" : "minecraft:donkey_spawn_egg" + }, + { + "id" : "minecraft:mule_spawn_egg" + }, + { + "id" : "minecraft:skeleton_horse_spawn_egg" + }, + { + "id" : "minecraft:zombie_horse_spawn_egg" + }, + { + "id" : "minecraft:tropical_fish_spawn_egg" + }, + { + "id" : "minecraft:cod_spawn_egg" + }, + { + "id" : "minecraft:pufferfish_spawn_egg" + }, + { + "id" : "minecraft:salmon_spawn_egg" + }, + { + "id" : "minecraft:dolphin_spawn_egg" + }, + { + "id" : "minecraft:turtle_spawn_egg" + }, + { + "id" : "minecraft:panda_spawn_egg" + }, + { + "id" : "minecraft:fox_spawn_egg" + }, + { + "id" : "minecraft:creeper_spawn_egg" + }, + { + "id" : "minecraft:enderman_spawn_egg" + }, + { + "id" : "minecraft:silverfish_spawn_egg" + }, + { + "id" : "minecraft:skeleton_spawn_egg" + }, + { + "id" : "minecraft:wither_skeleton_spawn_egg" + }, + { + "id" : "minecraft:stray_spawn_egg" + }, + { + "id" : "minecraft:slime_spawn_egg" + }, + { + "id" : "minecraft:spider_spawn_egg" + }, + { + "id" : "minecraft:zombie_spawn_egg" + }, + { + "id" : "minecraft:zombie_pigman_spawn_egg" + }, + { + "id" : "minecraft:husk_spawn_egg" + }, + { + "id" : "minecraft:drowned_spawn_egg" + }, + { + "id" : "minecraft:squid_spawn_egg" + }, + { + "id" : "minecraft:glow_squid_spawn_egg" + }, + { + "id" : "minecraft:cave_spider_spawn_egg" + }, + { + "id" : "minecraft:witch_spawn_egg" + }, + { + "id" : "minecraft:guardian_spawn_egg" + }, + { + "id" : "minecraft:elder_guardian_spawn_egg" + }, + { + "id" : "minecraft:endermite_spawn_egg" + }, + { + "id" : "minecraft:magma_cube_spawn_egg" + }, + { + "id" : "minecraft:strider_spawn_egg" + }, + { + "id" : "minecraft:hoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_spawn_egg" + }, + { + "id" : "minecraft:zoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_brute_spawn_egg" + }, + { + "id" : "minecraft:goat_spawn_egg" + }, + { + "id" : "minecraft:axolotl_spawn_egg" + }, + { + "id" : "minecraft:warden_spawn_egg" + }, + { + "id" : "minecraft:allay_spawn_egg" + }, + { + "id" : "minecraft:frog_spawn_egg" + }, + { + "id" : "minecraft:tadpole_spawn_egg" + }, + { + "id" : "minecraft:trader_llama_spawn_egg" + }, + { + "id" : "minecraft:ghast_spawn_egg" + }, + { + "id" : "minecraft:blaze_spawn_egg" + }, + { + "id" : "minecraft:shulker_spawn_egg" + }, + { + "id" : "minecraft:vindicator_spawn_egg" + }, + { + "id" : "minecraft:evoker_spawn_egg" + }, + { + "id" : "minecraft:vex_spawn_egg" + }, + { + "id" : "minecraft:villager_spawn_egg" + }, + { + "id" : "minecraft:wandering_trader_spawn_egg" + }, + { + "id" : "minecraft:zombie_villager_spawn_egg" + }, + { + "id" : "minecraft:phantom_spawn_egg" + }, + { + "id" : "minecraft:pillager_spawn_egg" + }, + { + "id" : "minecraft:ravager_spawn_egg" + }, + { + "id" : "minecraft:obsidian", + "blockRuntimeId" : 428 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 6722 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 7017 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 5831 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 7037 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 8009 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 3836 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 4530 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 5505 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 629 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 630 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5237 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5238 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5239 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5240 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5241 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5242 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5243 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5244 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5245 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5246 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 7036 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 7132 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 3613 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 4389 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 5832 + }, + { + "id" : "minecraft:leather_helmet" + }, + { + "id" : "minecraft:chainmail_helmet" + }, + { + "id" : "minecraft:iron_helmet" + }, + { + "id" : "minecraft:golden_helmet" + }, + { + "id" : "minecraft:diamond_helmet" + }, + { + "id" : "minecraft:netherite_helmet" + }, + { + "id" : "minecraft:leather_chestplate" + }, + { + "id" : "minecraft:chainmail_chestplate" + }, + { + "id" : "minecraft:iron_chestplate" + }, + { + "id" : "minecraft:golden_chestplate" + }, + { + "id" : "minecraft:diamond_chestplate" + }, + { + "id" : "minecraft:netherite_chestplate" + }, + { + "id" : "minecraft:leather_leggings" + }, + { + "id" : "minecraft:chainmail_leggings" + }, + { + "id" : "minecraft:iron_leggings" + }, + { + "id" : "minecraft:golden_leggings" + }, + { + "id" : "minecraft:diamond_leggings" + }, + { + "id" : "minecraft:netherite_leggings" + }, + { + "id" : "minecraft:leather_boots" + }, + { + "id" : "minecraft:chainmail_boots" + }, + { + "id" : "minecraft:iron_boots" + }, + { + "id" : "minecraft:golden_boots" + }, + { + "id" : "minecraft:diamond_boots" + }, + { + "id" : "minecraft:netherite_boots" + }, + { + "id" : "minecraft:wooden_sword" + }, + { + "id" : "minecraft:stone_sword" + }, + { + "id" : "minecraft:iron_sword" + }, + { + "id" : "minecraft:golden_sword" + }, + { + "id" : "minecraft:diamond_sword" + }, + { + "id" : "minecraft:netherite_sword" + }, + { + "id" : "minecraft:wooden_axe" + }, + { + "id" : "minecraft:stone_axe" + }, + { + "id" : "minecraft:iron_axe" + }, + { + "id" : "minecraft:golden_axe" + }, + { + "id" : "minecraft:diamond_axe" + }, + { + "id" : "minecraft:netherite_axe" + }, + { + "id" : "minecraft:wooden_pickaxe" + }, + { + "id" : "minecraft:stone_pickaxe" + }, + { + "id" : "minecraft:iron_pickaxe" + }, + { + "id" : "minecraft:golden_pickaxe" + }, + { + "id" : "minecraft:diamond_pickaxe" + }, + { + "id" : "minecraft:netherite_pickaxe" + }, + { + "id" : "minecraft:wooden_shovel" + }, + { + "id" : "minecraft:stone_shovel" + }, + { + "id" : "minecraft:iron_shovel" + }, + { + "id" : "minecraft:golden_shovel" + }, + { + "id" : "minecraft:diamond_shovel" + }, + { + "id" : "minecraft:netherite_shovel" + }, + { + "id" : "minecraft:wooden_hoe" + }, + { + "id" : "minecraft:stone_hoe" + }, + { + "id" : "minecraft:iron_hoe" + }, + { + "id" : "minecraft:golden_hoe" + }, + { + "id" : "minecraft:diamond_hoe" + }, + { + "id" : "minecraft:netherite_hoe" + }, + { + "id" : "minecraft:bow" + }, + { + "id" : "minecraft:crossbow" + }, + { + "id" : "minecraft:arrow" + }, + { + "id" : "minecraft:arrow", + "damage" : 6 + }, + { + "id" : "minecraft:arrow", + "damage" : 7 + }, + { + "id" : "minecraft:arrow", + "damage" : 8 + }, + { + "id" : "minecraft:arrow", + "damage" : 9 + }, + { + "id" : "minecraft:arrow", + "damage" : 10 + }, + { + "id" : "minecraft:arrow", + "damage" : 11 + }, + { + "id" : "minecraft:arrow", + "damage" : 12 + }, + { + "id" : "minecraft:arrow", + "damage" : 13 + }, + { + "id" : "minecraft:arrow", + "damage" : 14 + }, + { + "id" : "minecraft:arrow", + "damage" : 15 + }, + { + "id" : "minecraft:arrow", + "damage" : 16 + }, + { + "id" : "minecraft:arrow", + "damage" : 17 + }, + { + "id" : "minecraft:arrow", + "damage" : 18 + }, + { + "id" : "minecraft:arrow", + "damage" : 19 + }, + { + "id" : "minecraft:arrow", + "damage" : 20 + }, + { + "id" : "minecraft:arrow", + "damage" : 21 + }, + { + "id" : "minecraft:arrow", + "damage" : 22 + }, + { + "id" : "minecraft:arrow", + "damage" : 23 + }, + { + "id" : "minecraft:arrow", + "damage" : 24 + }, + { + "id" : "minecraft:arrow", + "damage" : 25 + }, + { + "id" : "minecraft:arrow", + "damage" : 26 + }, + { + "id" : "minecraft:arrow", + "damage" : 27 + }, + { + "id" : "minecraft:arrow", + "damage" : 28 + }, + { + "id" : "minecraft:arrow", + "damage" : 29 + }, + { + "id" : "minecraft:arrow", + "damage" : 30 + }, + { + "id" : "minecraft:arrow", + "damage" : 31 + }, + { + "id" : "minecraft:arrow", + "damage" : 32 + }, + { + "id" : "minecraft:arrow", + "damage" : 33 + }, + { + "id" : "minecraft:arrow", + "damage" : 34 + }, + { + "id" : "minecraft:arrow", + "damage" : 35 + }, + { + "id" : "minecraft:arrow", + "damage" : 36 + }, + { + "id" : "minecraft:arrow", + "damage" : 37 + }, + { + "id" : "minecraft:arrow", + "damage" : 38 + }, + { + "id" : "minecraft:arrow", + "damage" : 39 + }, + { + "id" : "minecraft:arrow", + "damage" : 40 + }, + { + "id" : "minecraft:arrow", + "damage" : 41 + }, + { + "id" : "minecraft:arrow", + "damage" : 42 + }, + { + "id" : "minecraft:arrow", + "damage" : 43 + }, + { + "id" : "minecraft:shield" + }, + { + "id" : "minecraft:cooked_chicken" + }, + { + "id" : "minecraft:cooked_porkchop" + }, + { + "id" : "minecraft:cooked_beef" + }, + { + "id" : "minecraft:cooked_mutton" + }, + { + "id" : "minecraft:cooked_rabbit" + }, + { + "id" : "minecraft:cooked_cod" + }, + { + "id" : "minecraft:cooked_salmon" + }, + { + "id" : "minecraft:bread" + }, + { + "id" : "minecraft:mushroom_stew" + }, + { + "id" : "minecraft:beetroot_soup" + }, + { + "id" : "minecraft:rabbit_stew" + }, + { + "id" : "minecraft:baked_potato" + }, + { + "id" : "minecraft:cookie" + }, + { + "id" : "minecraft:pumpkin_pie" + }, + { + "id" : "minecraft:cake" + }, + { + "id" : "minecraft:dried_kelp" + }, + { + "id" : "minecraft:fishing_rod" + }, + { + "id" : "minecraft:carrot_on_a_stick" + }, + { + "id" : "minecraft:warped_fungus_on_a_stick" + }, + { + "id" : "minecraft:snowball" + }, + { + "id" : "minecraft:shears" + }, + { + "id" : "minecraft:flint_and_steel" + }, + { + "id" : "minecraft:lead" + }, + { + "id" : "minecraft:clock" + }, + { + "id" : "minecraft:compass" + }, + { + "id" : "minecraft:recovery_compass" + }, + { + "id" : "minecraft:goat_horn" + }, + { + "id" : "minecraft:goat_horn", + "damage" : 1 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 2 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 3 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 4 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 5 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 6 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 7 + }, + { + "id" : "minecraft:empty_map" + }, + { + "id" : "minecraft:empty_map", + "damage" : 2 + }, + { + "id" : "minecraft:saddle" + }, + { + "id" : "minecraft:leather_horse_armor" + }, + { + "id" : "minecraft:iron_horse_armor" + }, + { + "id" : "minecraft:golden_horse_armor" + }, + { + "id" : "minecraft:diamond_horse_armor" + }, + { + "id" : "minecraft:trident" + }, + { + "id" : "minecraft:turtle_helmet" + }, + { + "id" : "minecraft:elytra" + }, + { + "id" : "minecraft:totem_of_undying" + }, + { + "id" : "minecraft:glass_bottle" + }, + { + "id" : "minecraft:experience_bottle" + }, + { + "id" : "minecraft:potion" + }, + { + "id" : "minecraft:potion", + "damage" : 1 + }, + { + "id" : "minecraft:potion", + "damage" : 2 + }, + { + "id" : "minecraft:potion", + "damage" : 3 + }, + { + "id" : "minecraft:potion", + "damage" : 4 + }, + { + "id" : "minecraft:potion", + "damage" : 5 + }, + { + "id" : "minecraft:potion", + "damage" : 6 + }, + { + "id" : "minecraft:potion", + "damage" : 7 + }, + { + "id" : "minecraft:potion", + "damage" : 8 + }, + { + "id" : "minecraft:potion", + "damage" : 9 + }, + { + "id" : "minecraft:potion", + "damage" : 10 + }, + { + "id" : "minecraft:potion", + "damage" : 11 + }, + { + "id" : "minecraft:potion", + "damage" : 12 + }, + { + "id" : "minecraft:potion", + "damage" : 13 + }, + { + "id" : "minecraft:potion", + "damage" : 14 + }, + { + "id" : "minecraft:potion", + "damage" : 15 + }, + { + "id" : "minecraft:potion", + "damage" : 16 + }, + { + "id" : "minecraft:potion", + "damage" : 17 + }, + { + "id" : "minecraft:potion", + "damage" : 18 + }, + { + "id" : "minecraft:potion", + "damage" : 19 + }, + { + "id" : "minecraft:potion", + "damage" : 20 + }, + { + "id" : "minecraft:potion", + "damage" : 21 + }, + { + "id" : "minecraft:potion", + "damage" : 22 + }, + { + "id" : "minecraft:potion", + "damage" : 23 + }, + { + "id" : "minecraft:potion", + "damage" : 24 + }, + { + "id" : "minecraft:potion", + "damage" : 25 + }, + { + "id" : "minecraft:potion", + "damage" : 26 + }, + { + "id" : "minecraft:potion", + "damage" : 27 + }, + { + "id" : "minecraft:potion", + "damage" : 28 + }, + { + "id" : "minecraft:potion", + "damage" : 29 + }, + { + "id" : "minecraft:potion", + "damage" : 30 + }, + { + "id" : "minecraft:potion", + "damage" : 31 + }, + { + "id" : "minecraft:potion", + "damage" : 32 + }, + { + "id" : "minecraft:potion", + "damage" : 33 + }, + { + "id" : "minecraft:potion", + "damage" : 34 + }, + { + "id" : "minecraft:potion", + "damage" : 35 + }, + { + "id" : "minecraft:potion", + "damage" : 36 + }, + { + "id" : "minecraft:potion", + "damage" : 37 + }, + { + "id" : "minecraft:potion", + "damage" : 38 + }, + { + "id" : "minecraft:potion", + "damage" : 39 + }, + { + "id" : "minecraft:potion", + "damage" : 40 + }, + { + "id" : "minecraft:potion", + "damage" : 41 + }, + { + "id" : "minecraft:potion", + "damage" : 42 + }, + { + "id" : "minecraft:splash_potion" + }, + { + "id" : "minecraft:splash_potion", + "damage" : 1 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 2 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 3 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 4 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 5 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 6 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 7 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 8 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 9 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 10 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 11 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 12 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 13 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 14 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 15 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 16 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 17 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 18 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 19 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 20 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 21 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 22 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 23 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 24 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 25 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 26 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 27 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 28 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 29 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 30 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 31 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 32 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 33 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 34 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 35 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 36 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 37 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 38 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 39 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 40 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 41 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 42 + }, + { + "id" : "minecraft:lingering_potion" + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 1 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 2 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 3 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 4 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 5 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 6 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 7 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 8 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 9 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 10 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 11 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 12 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 13 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 14 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 15 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 16 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 17 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 18 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 19 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 20 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 21 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 22 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 23 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 24 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 25 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 26 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 27 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 28 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 29 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 30 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 31 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 32 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 33 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 34 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 35 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 36 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 37 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 38 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 39 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 40 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 41 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 42 + }, + { + "id" : "minecraft:spyglass" + }, + { + "id" : "minecraft:stick" + }, + { + "id" : "minecraft:bed" + }, + { + "id" : "minecraft:bed", + "damage" : 8 + }, + { + "id" : "minecraft:bed", + "damage" : 7 + }, + { + "id" : "minecraft:bed", + "damage" : 15 + }, + { + "id" : "minecraft:bed", + "damage" : 12 + }, + { + "id" : "minecraft:bed", + "damage" : 14 + }, + { + "id" : "minecraft:bed", + "damage" : 1 + }, + { + "id" : "minecraft:bed", + "damage" : 4 + }, + { + "id" : "minecraft:bed", + "damage" : 5 + }, + { + "id" : "minecraft:bed", + "damage" : 13 + }, + { + "id" : "minecraft:bed", + "damage" : 9 + }, + { + "id" : "minecraft:bed", + "damage" : 3 + }, + { + "id" : "minecraft:bed", + "damage" : 11 + }, + { + "id" : "minecraft:bed", + "damage" : 10 + }, + { + "id" : "minecraft:bed", + "damage" : 2 + }, + { + "id" : "minecraft:bed", + "damage" : 6 + }, + { + "id" : "minecraft:torch", + "blockRuntimeId" : 724 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 4644 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 5855 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 7074 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 5749 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 7403 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 5300 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 362 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 418 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 4569 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 6192 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 6368 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 7370 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 939 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 6224 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 7726 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 7038 + }, + { + "id" : "minecraft:blue_candle" + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 5875 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 686 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 4681 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 171 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 5854 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 8288 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 5833 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 3726 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 6108 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 7802 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 7567 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 647 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 681 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6634 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6638 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6642 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 8039 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 6723 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 6671 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 6940 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 5415 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 7115 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 5583 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 4369 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 4518 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 3681 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5316 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5324 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5323 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5331 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5328 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5330 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5317 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5320 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5321 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5329 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5325 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5319 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5327 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5326 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5318 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5322 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 346 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 4874 + }, + { + "id" : "minecraft:music_disc_13" + }, + { + "id" : "minecraft:music_disc_cat" + }, + { + "id" : "minecraft:music_disc_blocks" + }, + { + "id" : "minecraft:music_disc_chirp" + }, + { + "id" : "minecraft:music_disc_far" + }, + { + "id" : "minecraft:music_disc_mall" + }, + { + "id" : "minecraft:music_disc_mellohi" + }, + { + "id" : "minecraft:music_disc_stal" + }, + { + "id" : "minecraft:music_disc_strad" + }, + { + "id" : "minecraft:music_disc_ward" + }, + { + "id" : "minecraft:music_disc_11" + }, + { + "id" : "minecraft:music_disc_wait" + }, + { + "id" : "minecraft:music_disc_otherside" + }, + { + "id" : "minecraft:music_disc_5" + }, + { + "id" : "minecraft:music_disc_pigstep" + }, + { + "id" : "minecraft:disc_fragment_5" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 3885 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 251 + }, + { + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 7546 + }, + { + "id" : "minecraft:oak_sign" + }, + { + "id" : "minecraft:spruce_sign" + }, + { + "id" : "minecraft:birch_sign" + }, + { + "id" : "minecraft:jungle_sign" + }, + { + "id" : "minecraft:acacia_sign" + }, + { + "id" : "minecraft:dark_oak_sign" + }, + { + "id" : "minecraft:mangrove_sign" + }, + { + "id" : "minecraft:crimson_sign" + }, + { + "id" : "minecraft:warped_sign" + }, + { + "id" : "minecraft:painting" + }, + { + "id" : "minecraft:frame" + }, + { + "id" : "minecraft:glow_frame" + }, + { + "id" : "minecraft:honey_bottle" + }, + { + "id" : "minecraft:flower_pot" + }, + { + "id" : "minecraft:bowl" + }, + { + "id" : "minecraft:bucket" + }, + { + "id" : "minecraft:milk_bucket" + }, + { + "id" : "minecraft:water_bucket" + }, + { + "id" : "minecraft:lava_bucket" + }, + { + "id" : "minecraft:cod_bucket" + }, + { + "id" : "minecraft:salmon_bucket" + }, + { + "id" : "minecraft:tropical_fish_bucket" + }, + { + "id" : "minecraft:pufferfish_bucket" + }, + { + "id" : "minecraft:powder_snow_bucket" + }, + { + "id" : "minecraft:axolotl_bucket" + }, + { + "id" : "minecraft:tadpole_bucket" + }, + { + "id" : "minecraft:skull", + "damage" : 3 + }, + { + "id" : "minecraft:skull", + "damage" : 2 + }, + { + "id" : "minecraft:skull", + "damage" : 4 + }, + { + "id" : "minecraft:skull", + "damage" : 5 + }, + { + "id" : "minecraft:skull" + }, + { + "id" : "minecraft:skull", + "damage" : 1 + }, + { + "id" : "minecraft:beacon", + "blockRuntimeId" : 145 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 6908 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 4232 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 7574 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 6077 + }, + { + "id" : "minecraft:coal" + }, + { + "id" : "minecraft:charcoal" + }, + { + "id" : "minecraft:diamond" + }, + { + "id" : "minecraft:iron_nugget" + }, + { + "id" : "minecraft:raw_iron" + }, + { + "id" : "minecraft:raw_gold" + }, + { + "id" : "minecraft:raw_copper" + }, + { + "id" : "minecraft:copper_ingot" + }, + { + "id" : "minecraft:iron_ingot" + }, + { + "id" : "minecraft:netherite_scrap" + }, + { + "id" : "minecraft:netherite_ingot" + }, + { + "id" : "minecraft:gold_nugget" + }, + { + "id" : "minecraft:gold_ingot" + }, + { + "id" : "minecraft:emerald" + }, + { + "id" : "minecraft:quartz" + }, + { + "id" : "minecraft:clay_ball" + }, + { + "id" : "minecraft:brick" + }, + { + "id" : "minecraft:netherbrick" + }, + { + "id" : "minecraft:prismarine_shard" + }, + { + "id" : "minecraft:amethyst_shard" + }, + { + "id" : "minecraft:prismarine_crystals" + }, + { + "id" : "minecraft:nautilus_shell" + }, + { + "id" : "minecraft:heart_of_the_sea" + }, + { + "id" : "minecraft:scute" + }, + { + "id" : "minecraft:phantom_membrane" + }, + { + "id" : "minecraft:string" + }, + { + "id" : "minecraft:feather" + }, + { + "id" : "minecraft:flint" + }, + { + "id" : "minecraft:gunpowder" + }, + { + "id" : "minecraft:leather" + }, + { + "id" : "minecraft:rabbit_hide" + }, + { + "id" : "minecraft:rabbit_foot" + }, + { + "id" : "minecraft:fire_charge" + }, + { + "id" : "minecraft:blaze_rod" + }, + { + "id" : "minecraft:blaze_powder" + }, + { + "id" : "minecraft:magma_cream" + }, + { + "id" : "minecraft:fermented_spider_eye" + }, + { + "id" : "minecraft:echo_shard" + }, + { + "id" : "minecraft:dragon_breath" + }, + { + "id" : "minecraft:shulker_shell" + }, + { + "id" : "minecraft:ghast_tear" + }, + { + "id" : "minecraft:slime_ball" + }, + { + "id" : "minecraft:ender_pearl" + }, + { + "id" : "minecraft:ender_eye" + }, + { + "id" : "minecraft:nether_star" + }, + { + "id" : "minecraft:end_rod", + "blockRuntimeId" : 5891 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 1176 + }, + { + "id" : "minecraft:end_crystal" + }, + { + "id" : "minecraft:paper" + }, + { + "id" : "minecraft:book" + }, + { + "id" : "minecraft:writable_book" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:oak_boat" + }, + { + "id" : "minecraft:spruce_boat" + }, + { + "id" : "minecraft:birch_boat" + }, + { + "id" : "minecraft:jungle_boat" + }, + { + "id" : "minecraft:acacia_boat" + }, + { + "id" : "minecraft:dark_oak_boat" + }, + { + "id" : "minecraft:mangrove_boat" + }, + { + "id" : "minecraft:oak_chest_boat" + }, + { + "id" : "minecraft:spruce_chest_boat" + }, + { + "id" : "minecraft:birch_chest_boat" + }, + { + "id" : "minecraft:jungle_chest_boat" + }, + { + "id" : "minecraft:acacia_chest_boat" + }, + { + "id" : "minecraft:dark_oak_chest_boat" + }, + { + "id" : "minecraft:mangrove_chest_boat" + }, + { + "id" : "minecraft:rail", + "blockRuntimeId" : 3920 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 5332 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 4132 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 309 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 3776 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 3525 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 6514 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 6391 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 4321 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 7766 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 116 + }, + { + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 7231 + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 93 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 7062 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 596 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 4432 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 7250 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 7790 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 5914 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 8063 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 3759 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 3555 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 3635 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 5247 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 5956 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 3869 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 8268 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 256 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 3886 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 3665 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 1160 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 6232 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 3513 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 4197 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 7385 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 8013 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 922 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 4364 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 6707 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 3826 + }, + { + "id" : "minecraft:banner" + }, + { + "id" : "minecraft:banner", + "damage" : 8 + }, + { + "id" : "minecraft:banner", + "damage" : 7 + }, + { + "id" : "minecraft:banner", + "damage" : 15 + }, + { + "id" : "minecraft:banner", + "damage" : 12 + }, + { + "id" : "minecraft:banner", + "damage" : 14 + }, + { + "id" : "minecraft:banner", + "damage" : 1 + }, + { + "id" : "minecraft:banner", + "damage" : 4 + }, + { + "id" : "minecraft:banner", + "damage" : 5 + }, + { + "id" : "minecraft:banner", + "damage" : 13 + }, + { + "id" : "minecraft:banner", + "damage" : 9 + }, + { + "id" : "minecraft:banner", + "damage" : 3 + }, + { + "id" : "minecraft:banner", + "damage" : 11 + }, + { + "id" : "minecraft:banner", + "damage" : 10 + }, + { + "id" : "minecraft:banner", + "damage" : 2 + }, + { + "id" : "minecraft:banner", + "damage" : 6 + }, + { + "id" : "minecraft:banner", + "damage" : 15, + "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id" : "minecraft:creeper_banner_pattern" + }, + { + "id" : "minecraft:skull_banner_pattern" + }, + { + "id" : "minecraft:flower_banner_pattern" + }, + { + "id" : "minecraft:mojang_banner_pattern" + }, + { + "id" : "minecraft:field_masoned_banner_pattern" + }, + { + "id" : "minecraft:bordure_indented_banner_pattern" + }, + { + "id" : "minecraft:piglin_banner_pattern" + }, + { + "id" : "minecraft:globe_banner_pattern" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_star", + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 8, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 7, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 15, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 12, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 14, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 1, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 4, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 5, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 13, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 9, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 3, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 11, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 10, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 2, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 6, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id" : "minecraft:chain" + }, + { + "id" : "minecraft:target", + "blockRuntimeId" : 6390 + }, + { + "id" : "minecraft:lodestone_compass" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index 2e3733aa6c0adaf4ce3cfa79567502b8333ae1cc..b3e6fdb77103286cf60af2a14913f213fc1afd69 100644 GIT binary patch delta 761 zcmXX^J8V*68101%6n-vTxRm!*JGelE%d3=kfztY@E*fK8nwpxX2_^&~)|k5B(5ZnQ z_c|J5e8q{OZF~%NG11Az#KEP;h;EJ1_}{Ni=YM?Xe2?>O7C#gv+nCk7y4+m7*|CiT zR0TisR)!bh3Yuyf@o|P{v0JXvHsb&Qk-o+&dF-&N+2Q8M`9p2N_c;WgQD*PTGrJ$-w9P3I`*t&bPE6J?rY#gf9Bxkj_NC#JbGoD+~C88v;ft)K+a9HY`cJEqB~bxV?r zTr(X>_Ut7bSQ^+fGQ1X(WcZ{rMR$vs;8^5u_QCh0PTw*STj{iyman%Lo6V&gOGaaR zb$MvOBwHafBEnZabnqmFX|XyuS%=dw!+-39PMl<~8XnSw&l{@{cn1f3pZZb;BT>et zk@Dcp_$lhJVU6jX>{xH`M#O+%-p2mvR~y7M-dv_77M5_&@*v delta 787 zcmX|9OK4M35N-aS`;zza?W;*lBpWqN%)d21np}4Y z*|^Y(2)c5mlrCJ>b|-=qrBo0q)TPik_de@tm~&^&oI7XMDxHeUIpDCiF1K5^=AByx zc)}`X_ArbEMtG=ATSN$6}u$SR}u&@x2&<{Sxx|1Q|p>neY zT?fOP!8&fM*@XbZ17C)R^S%te5P3gP#EOOCnUd%5S8rC#ko{RyD1Q}B!{t4q#ViO# z>O62IGeq5y85Tn_Zia>h(X2AU3G(5LAlM$%MaGpJcy^H9~T*D*JC}A~P?tWZ!shD?< z<1S5XxHE_`2D>|rMXFnNm2k&Z7bBal9JZtrginBro|DRmN=>n@@2rBStSa2O$_m6W ziJ#5_o;c6o3PsKpbC$5?Xpn2;)W_g(NVw!kV#j`pW><)FQtou9Ul)&K6}qkV*wN!Vve5H^8_=F+a$*UX26 zu(7@;DT;f>hGF0@=?nW^ diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_10.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_10.json new file mode 100644 index 000000000..00be1af06 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_10.json @@ -0,0 +1,4530 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 379 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 642 + }, + { + "name" : "minecraft:acacia_door", + "id" : 556 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 579 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:acacia_wall_sign", + "id" : -191 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:agent_spawn_egg", + "id" : 487 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 631 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 624 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:armor_stand", + "id" : 552 + }, + { + "name" : "minecraft:arrow", + "id" : 301 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 369 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 500 + }, + { + "name" : "minecraft:azalea", + "id" : -337 + }, + { + "name" : "minecraft:azalea_leaves", + "id" : -324 + }, + { + "name" : "minecraft:azalea_leaves_flowered", + "id" : -325 + }, + { + "name" : "minecraft:baked_potato", + "id" : 281 + }, + { + "name" : "minecraft:balloon", + "id" : 598 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:banner", + "id" : 567 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 651 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 418 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 494 + }, + { + "name" : "minecraft:beef", + "id" : 273 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:beetroot", + "id" : 285 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 295 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 286 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:big_dripleaf", + "id" : -323 + }, + { + "name" : "minecraft:birch_boat", + "id" : 376 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 639 + }, + { + "name" : "minecraft:birch_door", + "id" : 554 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 577 + }, + { + "name" : "minecraft:birch_stairs", + "id" : 135 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:black_candle", + "id" : -428 + }, + { + "name" : "minecraft:black_candle_cake", + "id" : -445 + }, + { + "name" : "minecraft:black_dye", + "id" : 395 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:blackstone", + "id" : -273 + }, + { + "name" : "minecraft:blackstone_double_slab", + "id" : -283 + }, + { + "name" : "minecraft:blackstone_slab", + "id" : -282 + }, + { + "name" : "minecraft:blackstone_stairs", + "id" : -276 + }, + { + "name" : "minecraft:blackstone_wall", + "id" : -277 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 429 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 423 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:bleach", + "id" : 596 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 399 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:boat", + "id" : 649 + }, + { + "name" : "minecraft:bone", + "id" : 415 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 411 + }, + { + "name" : "minecraft:book", + "id" : 387 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 586 + }, + { + "name" : "minecraft:bow", + "id" : 300 + }, + { + "name" : "minecraft:bowl", + "id" : 321 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 431 + }, + { + "name" : "minecraft:brick", + "id" : 383 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:brown_candle", + "id" : -425 + }, + { + "name" : "minecraft:brown_candle_cake", + "id" : -442 + }, + { + "name" : "minecraft:brown_dye", + "id" : 398 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 360 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 417 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camera", + "id" : 593 + }, + { + "name" : "minecraft:campfire", + "id" : 589 + }, + { + "name" : "minecraft:candle", + "id" : -412 + }, + { + "name" : "minecraft:candle_cake", + "id" : -429 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:carrot", + "id" : 279 + }, + { + "name" : "minecraft:carrot_on_a_stick", + "id" : 517 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:cauldron", + "id" : 432 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 457 + }, + { + "name" : "minecraft:cave_vines", + "id" : -322 + }, + { + "name" : "minecraft:cave_vines_body_with_berries", + "id" : -375 + }, + { + "name" : "minecraft:cave_vines_head_with_berries", + "id" : -376 + }, + { + "name" : "minecraft:chain", + "id" : 619 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 342 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 339 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 341 + }, + { + "name" : "minecraft:charcoal", + "id" : 303 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 389 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 435 + }, + { + "name" : "minecraft:chiseled_deepslate", + "id" : -395 + }, + { + "name" : "minecraft:chiseled_nether_bricks", + "id" : -302 + }, + { + "name" : "minecraft:chiseled_polished_blackstone", + "id" : -279 + }, + { + "name" : "minecraft:chorus_flower", + "id" : 200 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 558 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 384 + }, + { + "name" : "minecraft:client_request_placeholder_block", + "id" : -465 + }, + { + "name" : "minecraft:clock", + "id" : 393 + }, + { + "name" : "minecraft:coal", + "id" : 302 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:cobbled_deepslate", + "id" : -379 + }, + { + "name" : "minecraft:cobbled_deepslate_double_slab", + "id" : -396 + }, + { + "name" : "minecraft:cobbled_deepslate_slab", + "id" : -380 + }, + { + "name" : "minecraft:cobbled_deepslate_stairs", + "id" : -381 + }, + { + "name" : "minecraft:cobbled_deepslate_wall", + "id" : -382 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:cocoa_beans", + "id" : 412 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 364 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 480 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 563 + }, + { + "name" : "minecraft:comparator", + "id" : 522 + }, + { + "name" : "minecraft:compass", + "id" : 391 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 594 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:cooked_beef", + "id" : 274 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 276 + }, + { + "name" : "minecraft:cooked_cod", + "id" : 268 + }, + { + "name" : "minecraft:cooked_mutton", + "id" : 551 + }, + { + "name" : "minecraft:cooked_porkchop", + "id" : 263 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 289 + }, + { + "name" : "minecraft:cooked_salmon", + "id" : 269 + }, + { + "name" : "minecraft:cookie", + "id" : 271 + }, + { + "name" : "minecraft:copper_block", + "id" : -340 + }, + { + "name" : "minecraft:copper_ingot", + "id" : 504 + }, + { + "name" : "minecraft:copper_ore", + "id" : -311 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:cow_spawn_egg", + "id" : 436 + }, + { + "name" : "minecraft:cracked_deepslate_bricks", + "id" : -410 + }, + { + "name" : "minecraft:cracked_deepslate_tiles", + "id" : -409 + }, + { + "name" : "minecraft:cracked_nether_bricks", + "id" : -303 + }, + { + "name" : "minecraft:cracked_polished_blackstone_bricks", + "id" : -280 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, + { + "name" : "minecraft:creeper_banner_pattern", + "id" : 582 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 616 + }, + { + "name" : "minecraft:crimson_double_slab", + "id" : -266 + }, + { + "name" : "minecraft:crimson_fence", + "id" : -256 + }, + { + "name" : "minecraft:crimson_fence_gate", + "id" : -258 + }, + { + "name" : "minecraft:crimson_fungus", + "id" : -228 + }, + { + "name" : "minecraft:crimson_hyphae", + "id" : -299 + }, + { + "name" : "minecraft:crimson_nylium", + "id" : -232 + }, + { + "name" : "minecraft:crimson_planks", + "id" : -242 + }, + { + "name" : "minecraft:crimson_pressure_plate", + "id" : -262 + }, + { + "name" : "minecraft:crimson_roots", + "id" : -223 + }, + { + "name" : "minecraft:crimson_sign", + "id" : 614 + }, + { + "name" : "minecraft:crimson_slab", + "id" : -264 + }, + { + "name" : "minecraft:crimson_stairs", + "id" : -254 + }, + { + "name" : "minecraft:crimson_standing_sign", + "id" : -250 + }, + { + "name" : "minecraft:crimson_stem", + "id" : -225 + }, + { + "name" : "minecraft:crimson_trapdoor", + "id" : -246 + }, + { + "name" : "minecraft:crimson_wall_sign", + "id" : -252 + }, + { + "name" : "minecraft:crossbow", + "id" : 575 + }, + { + "name" : "minecraft:crying_obsidian", + "id" : -289 + }, + { + "name" : "minecraft:cut_copper", + "id" : -347 + }, + { + "name" : "minecraft:cut_copper_slab", + "id" : -361 + }, + { + "name" : "minecraft:cut_copper_stairs", + "id" : -354 + }, + { + "name" : "minecraft:cyan_candle", + "id" : -422 + }, + { + "name" : "minecraft:cyan_candle_cake", + "id" : -439 + }, + { + "name" : "minecraft:cyan_dye", + "id" : 401 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 380 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 643 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 557 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 580 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:daylight_detector_inverted", + "id" : 178 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:deepslate", + "id" : -378 + }, + { + "name" : "minecraft:deepslate_brick_double_slab", + "id" : -399 + }, + { + "name" : "minecraft:deepslate_brick_slab", + "id" : -392 + }, + { + "name" : "minecraft:deepslate_brick_stairs", + "id" : -393 + }, + { + "name" : "minecraft:deepslate_brick_wall", + "id" : -394 + }, + { + "name" : "minecraft:deepslate_bricks", + "id" : -391 + }, + { + "name" : "minecraft:deepslate_coal_ore", + "id" : -406 + }, + { + "name" : "minecraft:deepslate_copper_ore", + "id" : -408 + }, + { + "name" : "minecraft:deepslate_diamond_ore", + "id" : -405 + }, + { + "name" : "minecraft:deepslate_emerald_ore", + "id" : -407 + }, + { + "name" : "minecraft:deepslate_gold_ore", + "id" : -402 + }, + { + "name" : "minecraft:deepslate_iron_ore", + "id" : -401 + }, + { + "name" : "minecraft:deepslate_lapis_ore", + "id" : -400 + }, + { + "name" : "minecraft:deepslate_redstone_ore", + "id" : -403 + }, + { + "name" : "minecraft:deepslate_tile_double_slab", + "id" : -398 + }, + { + "name" : "minecraft:deepslate_tile_slab", + "id" : -388 + }, + { + "name" : "minecraft:deepslate_tile_stairs", + "id" : -389 + }, + { + "name" : "minecraft:deepslate_tile_wall", + "id" : -390 + }, + { + "name" : "minecraft:deepslate_tiles", + "id" : -387 + }, + { + "name" : "minecraft:deny", + "id" : 211 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:diamond", + "id" : 304 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 350 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 348 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 347 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 332 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 533 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 349 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 318 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 317 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 316 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 637 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 465 + }, + { + "name" : "minecraft:double_cut_copper_slab", + "id" : -368 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:double_stone_block_slab", + "id" : 43 + }, + { + "name" : "minecraft:double_stone_block_slab2", + "id" : 181 + }, + { + "name" : "minecraft:double_stone_block_slab3", + "id" : -167 + }, + { + "name" : "minecraft:double_stone_block_slab4", + "id" : -168 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 560 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:dried_kelp", + "id" : 270 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:dripstone_block", + "id" : -317 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:drowned_spawn_egg", + "id" : 483 + }, + { + "name" : "minecraft:dye", + "id" : 650 + }, + { + "name" : "minecraft:echo_shard", + "id" : 647 + }, + { + "name" : "minecraft:egg", + "id" : 390 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 471 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_1", + "id" : -12 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:element_104", + "id" : -115 + }, + { + "name" : "minecraft:element_105", + "id" : -116 + }, + { + "name" : "minecraft:element_106", + "id" : -117 + }, + { + "name" : "minecraft:element_107", + "id" : -118 + }, + { + "name" : "minecraft:element_108", + "id" : -119 + }, + { + "name" : "minecraft:element_109", + "id" : -120 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:element_112", + "id" : -123 + }, + { + "name" : "minecraft:element_113", + "id" : -124 + }, + { + "name" : "minecraft:element_114", + "id" : -125 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:element_116", + "id" : -127 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:element_118", + "id" : -129 + }, + { + "name" : "minecraft:element_12", + "id" : -23 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:element_14", + "id" : -25 + }, + { + "name" : "minecraft:element_15", + "id" : -26 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:element_18", + "id" : -29 + }, + { + "name" : "minecraft:element_19", + "id" : -30 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:element_20", + "id" : -31 + }, + { + "name" : "minecraft:element_21", + "id" : -32 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:element_25", + "id" : -36 + }, + { + "name" : "minecraft:element_26", + "id" : -37 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:element_28", + "id" : -39 + }, + { + "name" : "minecraft:element_29", + "id" : -40 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:element_33", + "id" : -44 + }, + { + "name" : "minecraft:element_34", + "id" : -45 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:element_36", + "id" : -47 + }, + { + "name" : "minecraft:element_37", + "id" : -48 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:element_39", + "id" : -50 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:element_40", + "id" : -51 + }, + { + "name" : "minecraft:element_41", + "id" : -52 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:element_45", + "id" : -56 + }, + { + "name" : "minecraft:element_46", + "id" : -57 + }, + { + "name" : "minecraft:element_47", + "id" : -58 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:element_54", + "id" : -65 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:element_56", + "id" : -67 + }, + { + "name" : "minecraft:element_57", + "id" : -68 + }, + { + "name" : "minecraft:element_58", + "id" : -69 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_60", + "id" : -71 + }, + { + "name" : "minecraft:element_61", + "id" : -72 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:element_64", + "id" : -75 + }, + { + "name" : "minecraft:element_65", + "id" : -76 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:element_67", + "id" : -78 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, + { + "name" : "minecraft:element_70", + "id" : -81 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:element_72", + "id" : -83 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:element_76", + "id" : -87 + }, + { + "name" : "minecraft:element_77", + "id" : -88 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:element_79", + "id" : -90 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_80", + "id" : -91 + }, + { + "name" : "minecraft:element_81", + "id" : -92 + }, + { + "name" : "minecraft:element_82", + "id" : -93 + }, + { + "name" : "minecraft:element_83", + "id" : -94 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:element_89", + "id" : -100 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:element_91", + "id" : -102 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:element_94", + "id" : -105 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:element_96", + "id" : -107 + }, + { + "name" : "minecraft:element_97", + "id" : -108 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:element_99", + "id" : -110 + }, + { + "name" : "minecraft:elytra", + "id" : 564 + }, + { + "name" : "minecraft:emerald", + "id" : 512 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 515 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 521 + }, + { + "name" : "minecraft:enchanted_golden_apple", + "id" : 259 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:end_bricks", + "id" : 206 + }, + { + "name" : "minecraft:end_crystal", + "id" : 653 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:ender_eye", + "id" : 433 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 422 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 508 + }, + { + "name" : "minecraft:exposed_copper", + "id" : -341 + }, + { + "name" : "minecraft:exposed_cut_copper", + "id" : -348 + }, + { + "name" : "minecraft:exposed_cut_copper_slab", + "id" : -362 + }, + { + "name" : "minecraft:exposed_cut_copper_stairs", + "id" : -355 + }, + { + "name" : "minecraft:exposed_double_cut_copper_slab", + "id" : -369 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:feather", + "id" : 327 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 428 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 585 + }, + { + "name" : "minecraft:filled_map", + "id" : 420 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 509 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 519 + }, + { + "name" : "minecraft:firework_star", + "id" : 520 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 392 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 356 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 299 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 581 + }, + { + "name" : "minecraft:flower_pot", + "id" : 514 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:frame", + "id" : 513 + }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 628 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 424 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 427 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 434 + }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 588 + }, + { + "name" : "minecraft:glow_berries", + "id" : 654 + }, + { + "name" : "minecraft:glow_frame", + "id" : 623 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 503 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:glow_stick", + "id" : 601 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 394 + }, + { + "name" : "minecraft:goat_horn", + "id" : 627 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 306 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 425 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 325 + }, + { + "name" : "minecraft:golden_boots", + "id" : 354 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 352 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 351 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 333 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 532 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 353 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 324 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 323 + }, + { + "name" : "minecraft:golden_sword", + "id" : 322 + }, + { + "name" : "minecraft:granite_stairs", + "id" : -169 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:grass_path", + "id" : 198 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:gray_candle", + "id" : -420 + }, + { + "name" : "minecraft:gray_candle_cake", + "id" : -437 + }, + { + "name" : "minecraft:gray_dye", + "id" : 403 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 397 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:gunpowder", + "id" : 328 + }, + { + "name" : "minecraft:hanging_roots", + "id" : -319 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:hardened_clay", + "id" : 172 + }, + { + "name" : "minecraft:hay_block", + "id" : 170 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 571 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 592 + }, + { + "name" : "minecraft:honeycomb", + "id" : 591 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 527 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 526 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 595 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 413 + }, + { + "name" : "minecraft:invisible_bedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 298 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 346 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 344 + }, + { + "name" : "minecraft:iron_door", + "id" : 372 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 343 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 331 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 531 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 305 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 345 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 569 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 297 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 296 + }, + { + "name" : "minecraft:iron_sword", + "id" : 307 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:item.birch_door", + "id" : 194 + }, + { + "name" : "minecraft:item.brewing_stand", + "id" : 117 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:item.cauldron", + "id" : 118 + }, + { + "name" : "minecraft:item.chain", + "id" : -286 + }, + { + "name" : "minecraft:item.crimson_door", + "id" : -244 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:item.glow_frame", + "id" : -339 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:item.mangrove_door", + "id" : -493 + }, + { + "name" : "minecraft:item.nether_sprouts", + "id" : -238 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:item.skull", + "id" : 144 + }, + { + "name" : "minecraft:item.soul_campfire", + "id" : -290 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:item.warped_door", + "id" : -245 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:jungle_boat", + "id" : 377 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 640 + }, + { + "name" : "minecraft:jungle_door", + "id" : 555 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 578 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:kelp", + "id" : 382 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 414 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 363 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 547 + }, + { + "name" : "minecraft:leather", + "id" : 381 + }, + { + "name" : "minecraft:leather_boots", + "id" : 338 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 336 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 335 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 530 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 337 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:light_blue_candle", + "id" : -416 + }, + { + "name" : "minecraft:light_blue_candle_cake", + "id" : -433 + }, + { + "name" : "minecraft:light_blue_dye", + "id" : 407 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 402 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:lightning_rod", + "id" : -312 + }, + { + "name" : "minecraft:lime_candle", + "id" : -418 + }, + { + "name" : "minecraft:lime_candle_cake", + "id" : -435 + }, + { + "name" : "minecraft:lime_dye", + "id" : 405 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 562 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:lit_deepslate_redstone_ore", + "id" : -404 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:llama_spawn_egg", + "id" : 473 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 602 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:magenta_candle", + "id" : -415 + }, + { + "name" : "minecraft:magenta_candle_cake", + "id" : -432 + }, + { + "name" : "minecraft:magenta_dye", + "id" : 408 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 430 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:mangrove_boat", + "id" : 635 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 644 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 633 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "name" : "minecraft:mangrove_leaves", + "id" : -472 + }, + { + "name" : "minecraft:mangrove_log", + "id" : -484 + }, + { + "name" : "minecraft:mangrove_planks", + "id" : -486 + }, + { + "name" : "minecraft:mangrove_pressure_plate", + "id" : -490 + }, + { + "name" : "minecraft:mangrove_propagule", + "id" : -474 + }, + { + "name" : "minecraft:mangrove_roots", + "id" : -482 + }, + { + "name" : "minecraft:mangrove_sign", + "id" : 634 + }, + { + "name" : "minecraft:mangrove_slab", + "id" : -489 + }, + { + "name" : "minecraft:mangrove_stairs", + "id" : -488 + }, + { + "name" : "minecraft:mangrove_standing_sign", + "id" : -494 + }, + { + "name" : "minecraft:mangrove_trapdoor", + "id" : -496 + }, + { + "name" : "minecraft:mangrove_wall_sign", + "id" : -495 + }, + { + "name" : "minecraft:mangrove_wood", + "id" : -497 + }, + { + "name" : "minecraft:medicine", + "id" : 599 + }, + { + "name" : "minecraft:medium_amethyst_bud", + "id" : -331 + }, + { + "name" : "minecraft:melon_block", + "id" : 103 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 293 + }, + { + "name" : "minecraft:melon_slice", + "id" : 272 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:milk_bucket", + "id" : 361 + }, + { + "name" : "minecraft:minecart", + "id" : 370 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 584 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 440 + }, + { + "name" : "minecraft:moss_block", + "id" : -320 + }, + { + "name" : "minecraft:moss_carpet", + "id" : -335 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:moving_block", + "id" : 250 + }, + { + "name" : "minecraft:mud", + "id" : -473 + }, + { + "name" : "minecraft:mud_brick_double_slab", + "id" : -479 + }, + { + "name" : "minecraft:mud_brick_slab", + "id" : -478 + }, + { + "name" : "minecraft:mud_brick_stairs", + "id" : -480 + }, + { + "name" : "minecraft:mud_brick_wall", + "id" : -481 + }, + { + "name" : "minecraft:mud_bricks", + "id" : -475 + }, + { + "name" : "minecraft:muddy_mangrove_roots", + "id" : -483 + }, + { + "name" : "minecraft:mule_spawn_egg", + "id" : 466 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 534 + }, + { + "name" : "minecraft:music_disc_5", + "id" : 636 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 536 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 535 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 537 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 538 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 539 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_otherside", + "id" : 626 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 620 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 543 + }, + { + "name" : "minecraft:mutton", + "id" : 550 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 548 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 570 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:nether_gold_ore", + "id" : -288 + }, + { + "name" : "minecraft:nether_sprouts", + "id" : 621 + }, + { + "name" : "minecraft:nether_star", + "id" : 518 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 523 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 607 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 612 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 610 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 609 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 608 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 603 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 611 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 613 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 605 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 604 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:normal_stone_stairs", + "id" : -180 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:npc_spawn_egg", + "id" : 470 + }, + { + "name" : "minecraft:oak_boat", + "id" : 375 + }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 638 + }, + { + "name" : "minecraft:oak_sign", + "id" : 358 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 409 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:oxidized_copper", + "id" : -343 + }, + { + "name" : "minecraft:oxidized_cut_copper", + "id" : -350 + }, + { + "name" : "minecraft:oxidized_cut_copper_slab", + "id" : -364 + }, + { + "name" : "minecraft:oxidized_cut_copper_stairs", + "id" : -357 + }, + { + "name" : "minecraft:oxidized_double_cut_copper_slab", + "id" : -371 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:packed_mud", + "id" : -477 + }, + { + "name" : "minecraft:painting", + "id" : 357 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:paper", + "id" : 386 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 478 + }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 574 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 404 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:piston_arm_collision", + "id" : 34 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:pointed_dripstone", + "id" : -308 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 282 + }, + { + "name" : "minecraft:polar_bear_spawn_egg", + "id" : 472 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:polished_basalt", + "id" : -235 + }, + { + "name" : "minecraft:polished_blackstone", + "id" : -291 + }, + { + "name" : "minecraft:polished_blackstone_brick_double_slab", + "id" : -285 + }, + { + "name" : "minecraft:polished_blackstone_brick_slab", + "id" : -284 + }, + { + "name" : "minecraft:polished_blackstone_brick_stairs", + "id" : -275 + }, + { + "name" : "minecraft:polished_blackstone_brick_wall", + "id" : -278 + }, + { + "name" : "minecraft:polished_blackstone_bricks", + "id" : -274 + }, + { + "name" : "minecraft:polished_blackstone_button", + "id" : -296 + }, + { + "name" : "minecraft:polished_blackstone_double_slab", + "id" : -294 + }, + { + "name" : "minecraft:polished_blackstone_pressure_plate", + "id" : -295 + }, + { + "name" : "minecraft:polished_blackstone_slab", + "id" : -293 + }, + { + "name" : "minecraft:polished_blackstone_stairs", + "id" : -292 + }, + { + "name" : "minecraft:polished_blackstone_wall", + "id" : -297 + }, + { + "name" : "minecraft:polished_deepslate", + "id" : -383 + }, + { + "name" : "minecraft:polished_deepslate_double_slab", + "id" : -397 + }, + { + "name" : "minecraft:polished_deepslate_slab", + "id" : -384 + }, + { + "name" : "minecraft:polished_deepslate_stairs", + "id" : -385 + }, + { + "name" : "minecraft:polished_deepslate_wall", + "id" : -386 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:popped_chorus_fruit", + "id" : 559 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 426 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 368 + }, + { + "name" : "minecraft:powered_comparator", + "id" : 150 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 549 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 565 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 481 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 284 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 292 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:purple_candle", + "id" : -423 + }, + { + "name" : "minecraft:purple_candle_cake", + "id" : -440 + }, + { + "name" : "minecraft:purple_dye", + "id" : 400 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 524 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:quartz_bricks", + "id" : -304 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:rabbit", + "id" : 288 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 528 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 529 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 597 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:raw_copper", + "id" : 507 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 506 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 505 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:recovery_compass", + "id" : 646 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 396 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:redstone", + "id" : 373 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:reinforced_deepslate", + "id" : -466 + }, + { + "name" : "minecraft:repeater", + "id" : 419 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 277 + }, + { + "name" : "minecraft:saddle", + "id" : 371 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 365 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 482 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:sculk", + "id" : -458 + }, + { + "name" : "minecraft:sculk_catalyst", + "id" : -460 + }, + { + "name" : "minecraft:sculk_sensor", + "id" : -307 + }, + { + "name" : "minecraft:sculk_shrieker", + "id" : -461 + }, + { + "name" : "minecraft:sculk_vein", + "id" : -459 + }, + { + "name" : "minecraft:scute", + "id" : 572 + }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:shears", + "id" : 421 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:shield", + "id" : 355 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 566 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skull", + "id" : 516 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 583 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 388 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 445 + }, + { + "name" : "minecraft:small_amethyst_bud", + "id" : -332 + }, + { + "name" : "minecraft:small_dripleaf_block", + "id" : -336 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:smooth_basalt", + "id" : -377 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 374 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 622 + }, + { + "name" : "minecraft:soul_fire", + "id" : -237 + }, + { + "name" : "minecraft:soul_lantern", + "id" : -269 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:soul_soil", + "id" : -236 + }, + { + "name" : "minecraft:soul_torch", + "id" : -268 + }, + { + "name" : "minecraft:sparkler", + "id" : 600 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 652 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:splash_potion", + "id" : 561 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 378 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 641 + }, + { + "name" : "minecraft:spruce_door", + "id" : 553 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 576 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:spruce_trapdoor", + "id" : -149 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:spyglass", + "id" : 625 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 450 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:stick", + "id" : 320 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:sticky_piston_arm_collision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 315 + }, + { + "name" : "minecraft:stone_block_slab", + "id" : 44 + }, + { + "name" : "minecraft:stone_block_slab2", + "id" : 182 + }, + { + "name" : "minecraft:stone_block_slab3", + "id" : -162 + }, + { + "name" : "minecraft:stone_block_slab4", + "id" : -166 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 330 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 314 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 313 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 312 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:string", + "id" : 326 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:stripped_crimson_hyphae", + "id" : -300 + }, + { + "name" : "minecraft:stripped_crimson_stem", + "id" : -240 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:stripped_jungle_log", + "id" : -7 + }, + { + "name" : "minecraft:stripped_mangrove_log", + "id" : -485 + }, + { + "name" : "minecraft:stripped_mangrove_wood", + "id" : -498 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_warped_hyphae", + "id" : -301 + }, + { + "name" : "minecraft:stripped_warped_stem", + "id" : -241 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:sugar", + "id" : 416 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 385 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 590 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 630 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 629 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:tinted_glass", + "id" : -334 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 525 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 568 + }, + { + "name" : "minecraft:trader_llama_spawn_egg", + "id" : 648 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 546 + }, + { + "name" : "minecraft:trip_wire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 366 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 573 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 485 + }, + { + "name" : "minecraft:twisting_vines", + "id" : -287 + }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:unknown", + "id" : -305 + }, + { + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:verdant_froglight", + "id" : -470 + }, + { + "name" : "minecraft:vex_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 632 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 617 + }, + { + "name" : "minecraft:warped_double_slab", + "id" : -267 + }, + { + "name" : "minecraft:warped_fence", + "id" : -257 + }, + { + "name" : "minecraft:warped_fence_gate", + "id" : -259 + }, + { + "name" : "minecraft:warped_fungus", + "id" : -229 + }, + { + "name" : "minecraft:warped_fungus_on_a_stick", + "id" : 618 + }, + { + "name" : "minecraft:warped_hyphae", + "id" : -298 + }, + { + "name" : "minecraft:warped_nylium", + "id" : -233 + }, + { + "name" : "minecraft:warped_planks", + "id" : -243 + }, + { + "name" : "minecraft:warped_pressure_plate", + "id" : -263 + }, + { + "name" : "minecraft:warped_roots", + "id" : -224 + }, + { + "name" : "minecraft:warped_sign", + "id" : 615 + }, + { + "name" : "minecraft:warped_slab", + "id" : -265 + }, + { + "name" : "minecraft:warped_stairs", + "id" : -255 + }, + { + "name" : "minecraft:warped_standing_sign", + "id" : -251 + }, + { + "name" : "minecraft:warped_stem", + "id" : -226 + }, + { + "name" : "minecraft:warped_trapdoor", + "id" : -247 + }, + { + "name" : "minecraft:warped_wall_sign", + "id" : -253 + }, + { + "name" : "minecraft:warped_wart_block", + "id" : -227 + }, + { + "name" : "minecraft:water", + "id" : 9 + }, + { + "name" : "minecraft:water_bucket", + "id" : 362 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:waxed_copper", + "id" : -344 + }, + { + "name" : "minecraft:waxed_cut_copper", + "id" : -351 + }, + { + "name" : "minecraft:waxed_cut_copper_slab", + "id" : -365 + }, + { + "name" : "minecraft:waxed_cut_copper_stairs", + "id" : -358 + }, + { + "name" : "minecraft:waxed_double_cut_copper_slab", + "id" : -372 + }, + { + "name" : "minecraft:waxed_exposed_copper", + "id" : -345 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper", + "id" : -352 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_slab", + "id" : -366 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_stairs", + "id" : -359 + }, + { + "name" : "minecraft:waxed_exposed_double_cut_copper_slab", + "id" : -373 + }, + { + "name" : "minecraft:waxed_oxidized_copper", + "id" : -446 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper", + "id" : -447 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_slab", + "id" : -449 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_stairs", + "id" : -448 + }, + { + "name" : "minecraft:waxed_oxidized_double_cut_copper_slab", + "id" : -450 + }, + { + "name" : "minecraft:waxed_weathered_copper", + "id" : -346 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper", + "id" : -353 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_slab", + "id" : -367 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_stairs", + "id" : -360 + }, + { + "name" : "minecraft:waxed_weathered_double_cut_copper_slab", + "id" : -374 + }, + { + "name" : "minecraft:weathered_copper", + "id" : -342 + }, + { + "name" : "minecraft:weathered_cut_copper", + "id" : -349 + }, + { + "name" : "minecraft:weathered_cut_copper_slab", + "id" : -363 + }, + { + "name" : "minecraft:weathered_cut_copper_stairs", + "id" : -356 + }, + { + "name" : "minecraft:weathered_double_cut_copper_slab", + "id" : -370 + }, + { + "name" : "minecraft:web", + "id" : 30 + }, + { + "name" : "minecraft:weeping_vines", + "id" : -231 + }, + { + "name" : "minecraft:wheat", + "id" : 334 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 410 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 359 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 329 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 310 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 309 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 308 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:writable_book", + "id" : 510 + }, + { + "name" : "minecraft:written_book", + "id" : 511 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 406 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 477 + } +] \ No newline at end of file diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 27e9c97df..012789123 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 27e9c97df1e9a2f9d1f05359a29181e6ee0810d2 +Subproject commit 0127891232742209b8470298dfd997249c506320 From 0efd04dd87183064f51de93bc93b7058aeec9b69 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:59:03 -0400 Subject: [PATCH 099/290] Initial code for `/geyser connectiontest` This command acts as a testing ground for debugging Unable to Connect to World. More checks will be added in the future. --- .../standalone/GeyserStandaloneBootstrap.java | 3 +- .../java/org/geysermc/geyser/GeyserImpl.java | 25 +-- .../geyser/command/CommandManager.java | 1 + .../defaults/ConnectionTestCommand.java | 142 ++++++++++++++++++ .../geysermc/geyser/util}/LoopbackUtil.java | 52 ++++--- .../org/geysermc/geyser/util/WebUtils.java | 22 +++ 6 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java rename {bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone => core/src/main/java/org/geysermc/geyser/util}/LoopbackUtil.java (52%) diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 1e84e13d9..ca41fbd72 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -51,6 +51,7 @@ import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.platform.standalone.command.GeyserCommandManager; import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; +import org.geysermc.geyser.util.LoopbackUtil; import java.io.File; import java.io.IOException; @@ -187,7 +188,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { geyserLogger = new GeyserStandaloneLogger(); - LoopbackUtil.checkLoopback(geyserLogger); + LoopbackUtil.checkAndApplyLoopback(geyserLogger); try { File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 0cea9fbac..4322dde59 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -73,8 +73,6 @@ import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.*; -import javax.naming.directory.Attribute; -import javax.naming.directory.InitialDirContext; import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -226,23 +224,12 @@ public class GeyserImpl implements GeyserApi { String remoteAddress = config.getRemote().getAddress(); // Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry. if (!remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) { - int remotePort; - try { - // Searches for a server address and a port from a SRV record of the specified host name - InitialDirContext ctx = new InitialDirContext(); - Attribute attr = ctx.getAttributes("dns:///_minecraft._tcp." + remoteAddress, new String[]{"SRV"}).get("SRV"); - // size > 0 = SRV entry found - if (attr != null && attr.size() > 0) { - String[] record = ((String) attr.get(0)).split(" "); - // Overwrites the existing address and port with that from the SRV record. - config.getRemote().setAddress(remoteAddress = record[3]); - config.getRemote().setPort(remotePort = Integer.parseInt(record[2])); - logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\""); - } - } catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes - logger.debug("Exception while trying to find an SRV record for the remote host."); - if (config.isDebugMode()) - ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record + String[] record = WebUtils.findSrvRecord(this, remoteAddress); + if (record != null) { + int remotePort = Integer.parseInt(record[2]); + config.getRemote().setAddress(remoteAddress = record[3]); + config.getRemote().setPort(remotePort); + logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\""); } } diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java index 60af8c4e5..38a86fdd0 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java @@ -55,6 +55,7 @@ public abstract class CommandManager { registerCommand(new StatisticsCommand(geyser, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); registerCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); registerCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); + registerCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); if (GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE) { registerCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java new file mode 100644 index 000000000..576d17128 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.command.defaults; + +import com.fasterxml.jackson.databind.JsonNode; +import org.geysermc.common.PlatformType; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.LoopbackUtil; +import org.geysermc.geyser.util.WebUtils; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.CompletableFuture; + +public class ConnectionTestCommand extends GeyserCommand { + private final GeyserImpl geyser; + + public ConnectionTestCommand(GeyserImpl geyser, String name, String description, String permission) { + super(name, description, permission); + this.geyser = geyser; + } + + @Override + public void execute(@Nullable GeyserSession session, CommandSender sender, String[] args) { + // Only allow the console to create dumps on Geyser Standalone + if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + return; + } + + if (args.length == 0) { + sender.sendMessage("Provide the Bedrock server IP you are trying to connect with. Example: `test.geysermc.org:19132`"); + return; + } + + // Still allow people to not supply a port and fallback to 19132 + String[] fullAddress = args[0].split(":", 2); + int port; + if (fullAddress.length == 2) { + port = Integer.parseInt(fullAddress[1]); + } else { + port = 19132; + } + + // Issue: do the ports not line up? + if (port != geyser.getConfig().getBedrock().getPort()) { + sender.sendMessage("The port you supplied (" + port + ") does not match the port supplied in Geyser's configuration (" + + geyser.getConfig().getBedrock().getPort() + "). You can change it under `bedrock` `port`."); + } + + // Issue: is the `bedrock` `address` in the config different? + if (!geyser.getConfig().getBedrock().getAddress().equals("0.0.0.0")) { + sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional."); + } + + // Issue: did someone turn on enable-proxy-protocol and they didn't mean it? + if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) { + sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " + + "Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled."); + } + + CompletableFuture.runAsync(() -> { + try { + // Issue: SRV record? + String ip = fullAddress[0]; + String[] record = WebUtils.findSrvRecord(geyser, ip); + if (record != null && !ip.equals(record[3]) && !record[2].equals(String.valueOf(port))) { + sender.sendMessage("Bedrock Edition does not support SRV records. Try connecting to your server using the address " + record[3] + " and the port " + record[2] + + ". If that fails, re-run this command with that address and port."); + return; + } + + // Issue: does Loopback need applying? + if (LoopbackUtil.needsLoopback(GeyserImpl.getInstance().getLogger())) { + sender.sendMessage("Loopback is not applied on this computer! You will have issues connecting from the same computer. " + + "See here for steps on how to resolve: " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/#using-geyser-on-the-same-computer"); + } + + // mcsrvstatus will likely be replaced in the future with our own service where we can also test + // around the OVH workaround without worrying about caching + JsonNode output = WebUtils.getJson("https://api.mcsrvstat.us/bedrock/2/" + args[0]); + + long cacheTime = output.get("debug").get("cachetime").asLong(); + String when; + if (cacheTime == 0) { + when = "now"; + } else { + when = ((System.currentTimeMillis() / 1000L) - cacheTime) + " seconds ago"; + } + + if (output.get("online").asBoolean()) { + sender.sendMessage("Your server is likely online as of " + when + "!"); + sendLinks(sender); + return; + } + + sender.sendMessage("Your server is likely unreachable from outside the network as of " + when + "."); + sendLinks(sender); + } catch (Exception e) { + sender.sendMessage("Error while trying to check your connection!"); + geyser.getLogger().error("Error while trying to check your connection!", e); + } + }); + } + + private void sendLinks(CommandSender sender) { + sender.sendMessage("If you still have issues, check to see if your hosting provider has a specific setup: " + + "https://wiki.geysermc.org/geyser/supported-hosting-providers/" + ", see this page: " + + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/" + ", or contact us on our Discord: " + "https://discord.gg/geysermc"); + } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } +} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java b/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java similarity index 52% rename from bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java rename to core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java index 6679c8950..b543e4a48 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java @@ -23,8 +23,9 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.platform.standalone; +package org.geysermc.geyser.util; +import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; @@ -32,32 +33,47 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; -public class LoopbackUtil { - private static final String checkExemption = "powershell -Command \"CheckNetIsolation LoopbackExempt -s\""; // Java's Exec feature runs as CMD, NetIsolation is only accessible from PowerShell. - private static final String loopbackCommand = "powershell -Command \"CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'\""; +public final class LoopbackUtil { + private static final String checkExemption = "CheckNetIsolation LoopbackExempt -s"; + private static final String loopbackCommand = "CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'"; + /** + * This string needs to be checked in the event Minecraft is not installed - no Minecraft string will be present in the checkExemption command. + */ + private static final String minecraftApplication = "S-1-15-2-1958404141-86561845-1752920682-3514627264-368642714-62675701-733520436"; private static final String startScript = "powershell -Command \"Start-Process 'cmd' -ArgumentList /c,%temp%/loopback_minecraft.bat -Verb runAs\""; - public static void checkLoopback(GeyserStandaloneLogger geyserLogger) { - if (System.getProperty("os.name").equalsIgnoreCase("Windows 10")) { + /** + * @return true if loopback is not addressed properly. + */ + public static boolean needsLoopback(GeyserLogger logger) { + String os = System.getProperty("os.name"); + if (os.equalsIgnoreCase("Windows 10") || os.equalsIgnoreCase("Windows 11")) { try { Process process = Runtime.getRuntime().exec(checkExemption); + process.waitFor(); InputStream is = process.getInputStream(); + StringBuilder sb = new StringBuilder(); - - while (process.isAlive()) { - if (is.available() != 0) { - sb.append((char) is.read()); - } + while (is.available() != 0) { + sb.append((char) is.read()); } - String result = sb.toString(); + return !sb.toString().contains(minecraftApplication); + } catch (Exception e) { + logger.error("Couldn't detect if loopback has been added on Windows!", e); + return true; + } + } + return false; + } - if (!result.contains("minecraftuwp")) { - Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes()); - Runtime.getRuntime().exec(startScript); + public static void checkAndApplyLoopback(GeyserLogger geyserLogger) { + if (needsLoopback(geyserLogger)) { + try { + Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes()); + Runtime.getRuntime().exec(startScript); - geyserLogger.info(ChatColor.AQUA + GeyserLocale.getLocaleStringLog("geyser.bootstrap.loopback.added")); - } + geyserLogger.info(ChatColor.AQUA + GeyserLocale.getLocaleStringLog("geyser.bootstrap.loopback.added")); } catch (Exception e) { e.printStackTrace(); @@ -66,4 +82,6 @@ public class LoopbackUtil { } } + private LoopbackUtil() { + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index fe479363f..f9574f08b 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -28,6 +28,9 @@ package org.geysermc.geyser.util; import com.fasterxml.jackson.databind.JsonNode; import org.geysermc.geyser.GeyserImpl; +import javax.annotation.Nullable; +import javax.naming.directory.Attribute; +import javax.naming.directory.InitialDirContext; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; @@ -170,4 +173,23 @@ public class WebUtils { return connectionToString(con); } + + @Nullable + public static String[] findSrvRecord(GeyserImpl geyser, String remoteAddress) { + try { + // Searches for a server address and a port from a SRV record of the specified host name + InitialDirContext ctx = new InitialDirContext(); + Attribute attr = ctx.getAttributes("dns:///_minecraft._tcp." + remoteAddress, new String[]{"SRV"}).get("SRV"); + // size > 0 = SRV entry found + if (attr != null && attr.size() > 0) { + return ((String) attr.get(0)).split(" "); + } + } catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes + if (geyser.getConfig().isDebugMode()) { + geyser.getLogger().debug("Exception while trying to find an SRV record for the remote host."); + ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record + } + } + return null; + } } From 25289a360672fe3ce03367def5c4d430f9e99376 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 22 Jul 2022 23:32:43 -0400 Subject: [PATCH 100/290] Error out gracefully when Velocity is outdated --- .../geyser/platform/velocity/GeyserVelocityPlugin.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 6645ef595..4a8a50da8 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -35,6 +35,7 @@ import com.velocitypowered.api.network.ListenerType; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.ProxyServer; import lombok.Getter; +import net.kyori.adventure.util.Codec; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -83,6 +84,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Override public void onEnable() { + try { + Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class); + } catch (NoSuchMethodException e) { + // velocitypowered.com has a build that is very outdated + logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " + + "that has likely been downloaded is very outdated and does not support 1.19."); + return; + } + GeyserLocale.init(this); try { From 76bb5d4d8811442aceeed2ad6efef97a370baf53 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 23 Jul 2022 10:50:43 -0400 Subject: [PATCH 101/290] Fix persistent FOV when walk speed is ever set to zero Fixes #3139 --- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 519eef3b5..d3e1b7a7b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1692,7 +1692,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { abilityLayer.setLayerType(AbilityLayer.Type.BASE); abilityLayer.setFlySpeed(flySpeed); - abilityLayer.setWalkSpeed(walkSpeed); + // https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10 + abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed); Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES); updateAbilitiesPacket.getAbilityLayers().add(abilityLayer); From 41273001d8acea0079e099bf8e4050bfdda04f34 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 24 Jul 2022 13:51:17 -0400 Subject: [PATCH 102/290] Fix chunks on Hypixel --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index c3fca5fc8..5c0e58f83 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -163,7 +163,7 @@ com.github.GeyserMC MCProtocolLib - 54fc9f0 + ecc04fd compile From a18ac29a9132ca7c81bf91509f3572a5acfad8ac Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 24 Jul 2022 19:32:22 -0400 Subject: [PATCH 103/290] Initial 1.19.1 Java support --- core/pom.xml | 6 ++--- .../geyser/session/GeyserSession.java | 10 ++++----- .../geysermc/geyser/text/ChatTypeEntry.java | 13 +++++------ .../geysermc/geyser/text/TextDecoration.java | 20 +++++++++-------- .../protocol/java/JavaCommandsTranslator.java | 4 ++-- .../protocol/java/JavaLoginTranslator.java | 22 +++---------------- .../java/JavaPlayerChatTranslator.java | 15 +++++-------- .../java/JavaSystemChatTranslator.java | 7 +----- 8 files changed, 35 insertions(+), 62 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 5c0e58f83..cd38a0dfc 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -161,9 +161,9 @@ compile - com.github.GeyserMC - MCProtocolLib - ecc04fd + com.github.steveice10 + mcprotocollib + 1.19.1-SNAPSHOT compile diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index d3e1b7a7b..be3dfc2e3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -123,9 +123,9 @@ import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; -import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; @@ -341,7 +341,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(8); + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); @Setter private int breakingBlock; @@ -564,8 +564,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.playerEntity = new SessionPlayerEntity(this); collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition()); - ChatTypeEntry.applyDefaults(chatTypes); - this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); @@ -1388,14 +1386,14 @@ public class GeyserSession implements GeyserConnection, CommandSender { * Sends a chat message to the Java server. */ public void sendChat(String message) { - sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false)); + sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false, Collections.emptyList(), null)); } /** * Sends a command to the Java server. */ public void sendCommand(String command) { - sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyMap(), false)); + sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), false, Collections.emptyList(), null)); } public void setServerRenderDistance(int renderDistance) { diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java index ad2514e09..c45de8f9f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -34,9 +34,7 @@ import javax.annotation.Nullable; public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable TextDecoration textDecoration) { private static final ChatTypeEntry CHAT = new ChatTypeEntry(TextPacket.Type.CHAT, null); - private static final ChatTypeEntry SYSTEM = new ChatTypeEntry(TextPacket.Type.CHAT, null); - private static final ChatTypeEntry TIP = new ChatTypeEntry(TextPacket.Type.CHAT, null); - private static final ChatTypeEntry RAW = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry RAW = new ChatTypeEntry(TextPacket.Type.RAW, null); /** * Apply defaults to a map so it isn't empty in the event a chat message is sent before the login packet. @@ -46,12 +44,11 @@ public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable // But, the only way this happens is if a chat message is sent to us before the login packet, which is rare. // So we'll just make sure chat ends up in the right place. chatTypes.put(BuiltinChatType.CHAT.ordinal(), CHAT); - chatTypes.put(BuiltinChatType.SYSTEM.ordinal(), SYSTEM); - chatTypes.put(BuiltinChatType.GAME_INFO.ordinal(), TIP); chatTypes.put(BuiltinChatType.SAY_COMMAND.ordinal(), RAW); - chatTypes.put(BuiltinChatType.MSG_COMMAND.ordinal(), RAW); - chatTypes.put(BuiltinChatType.TEAM_MSG_COMMAND.ordinal(), RAW); + chatTypes.put(BuiltinChatType.MSG_COMMAND_INCOMING.ordinal(), RAW); + chatTypes.put(BuiltinChatType.MSG_COMMAND_OUTGOING.ordinal(), RAW); + chatTypes.put(BuiltinChatType.TEAM_MSG_COMMAND_INCOMING.ordinal(), RAW); + chatTypes.put(BuiltinChatType.TEAM_MSG_COMMAND_OUTGOING.ordinal(), RAW); chatTypes.put(BuiltinChatType.EMOTE_COMMAND.ordinal(), RAW); - chatTypes.put(BuiltinChatType.TELLRAW_COMMAND.ordinal(), RAW); } } diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java index 296cacaf5..121e1b2b9 100644 --- a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -46,14 +46,16 @@ public final class TextDecoration { CompoundTag styleTag = tag.get("style"); Style.Builder builder = Style.style(); - StringTag color = styleTag.get("color"); - if (color != null) { - builder.color(NamedTextColor.NAMES.value(color.getValue())); - } - //TODO implement the rest - Tag italic = styleTag.get("italic"); - if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) { - builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); + if (styleTag != null) { + StringTag color = styleTag.get("color"); + if (color != null) { + builder.color(NamedTextColor.NAMES.value(color.getValue())); + } + //TODO implement the rest + Tag italic = styleTag.get("italic"); + if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) { + builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); + } } style = builder.build(); @@ -88,6 +90,6 @@ public final class TextDecoration { public enum Parameter { CONTENT, SENDER, - TEAM_NAME + TARGET } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index b6f7a2451..c9f192d3f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -131,7 +131,7 @@ public class JavaCommandsTranslator extends PacketTranslator= 1) { @@ -319,7 +319,7 @@ public class JavaCommandsTranslator extends PacketTranslator chatTypes = session.getChatTypes(); + Int2ObjectMap chatTypes = session.getChatTypes(); chatTypes.clear(); for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. @@ -77,21 +73,9 @@ public class JavaLoginTranslator extends PacketTranslator TextPacket.Type.CHAT; - case SYSTEM -> TextPacket.Type.SYSTEM; - case GAME_INFO -> TextPacket.Type.TIP; - default -> TextPacket.Type.RAW; - } : TextPacket.Type.RAW; - chatTypes.put(id, new ChatTypeEntry(bedrockType, textDecoration)); + chatTypes.put(id, textDecoration); } // If the player is already initialized and a join game packet is sent, they diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java index f9f4407d9..74b27d417 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java @@ -30,7 +30,6 @@ import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -45,18 +44,16 @@ public class JavaPlayerChatTranslator extends PacketTranslator parameters = decoration.parameters(); List args = new ArrayList<>(3); - if (parameters.contains(TextDecoration.Parameter.TEAM_NAME)) { - args.add(packet.getSenderTeamName()); + if (parameters.contains(TextDecoration.Parameter.TARGET)) { + args.add(packet.getTargetName()); } if (parameters.contains(TextDecoration.Parameter.SENDER)) { - args.add(packet.getSenderName()); + args.add(packet.getName()); } if (parameters.contains(TextDecoration.Parameter.CONTENT)) { args.add(message); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java index 2bc0d1442..b605dbbbc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java @@ -28,7 +28,6 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSystemChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -38,15 +37,11 @@ public class JavaSystemChatTranslator extends PacketTranslator Date: Sun, 24 Jul 2022 19:41:05 -0400 Subject: [PATCH 104/290] Empty villager trades are valid Fixes #3171 --- .../protocol/java/inventory/JavaMerchantOffersTranslator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index 1c9ded0c1..69f00b010 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -104,7 +104,9 @@ public class JavaMerchantOffersTranslator extends PacketTranslator Date: Wed, 27 Jul 2022 16:38:51 -0400 Subject: [PATCH 105/290] Compiles; bump version --- ap/pom.xml | 4 ++-- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 ++-- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 4 ++-- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 2 +- core/pom.xml | 14 +++++++------- pom.xml | 2 +- 13 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ap/pom.xml b/ap/pom.xml index 1be050e51..90bb1dc73 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT ap - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index ec0c8ac84..0eeb536ea 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 6842929e6..0071668bf 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index 50c7cb822..9b4816954 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index cd96fe6d0..4ec01539f 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 99e77f5af..0da863811 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index dffe9f578..25bcb23f9 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-spigot @@ -30,7 +30,7 @@ org.geysermc core - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index e0ea5c97d..25f709ec4 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index aca72d28c..5d27c8a2a 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 62b155c97..0c530b21e 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index f25943535..5326ca014 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT common diff --git a/core/pom.xml b/core/pom.xml index cd38a0dfc..b9cc75233 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT core @@ -29,19 +29,19 @@ org.geysermc ap - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT provided org.geysermc geyser-api - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile org.geysermc common - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT compile @@ -161,9 +161,9 @@ compile - com.github.steveice10 - mcprotocollib - 1.19.1-SNAPSHOT + com.github.GeyserMC + MCProtocolLib + 54e6f9e compile diff --git a/pom.xml b/pom.xml index 70924b7a0..1d99d93e0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.5-SNAPSHOT + 2.0.6-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From c914938acb99a3ddd6c6802f58ae281d9663a52c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 27 Jul 2022 16:55:57 -0400 Subject: [PATCH 106/290] Fix clientbound action serialization --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index b9cc75233..8977854cb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -163,7 +163,7 @@ com.github.GeyserMC MCProtocolLib - 54e6f9e + 9f78bd5 compile From 4163de9314204079def6d6f519648386b0cf17bd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 28 Jul 2022 17:45:38 -0400 Subject: [PATCH 107/290] Translate allay dancing --- .../geyser/entity/EntityDefinitions.java | 2 ++ .../entity/type/living/AllayEntity.java | 26 +++++++++++++++++-- .../inventory/item/StoredItemMappings.java | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index 52d9250ac..a552d0875 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -453,6 +453,8 @@ public final class EntityDefinitions { ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase) .type(EntityType.ALLAY) .height(0.6f).width(0.35f) + .addTranslator(MetadataType.BOOLEAN, AllayEntity::setDancing) + .addTranslator(MetadataType.BOOLEAN, AllayEntity::setCanDuplicate) .build(); BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase) .type(EntityType.BAT) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java index ab444c4ab..d37a67938 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; @@ -37,14 +39,27 @@ import javax.annotation.Nonnull; import java.util.UUID; public class AllayEntity extends MobEntity { + private boolean canDuplicate; + public AllayEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + public void setDancing(BooleanEntityMetadata entityMetadata) { + setFlag(EntityFlag.DANCING, entityMetadata.getPrimitiveValue()); + } + + public void setCanDuplicate(BooleanEntityMetadata entityMetadata) { + this.canDuplicate = entityMetadata.getPrimitiveValue(); + } + @Nonnull @Override protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { - if (!this.hand.isValid() && !itemInHand.isEmpty()) { + if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) { + // Maybe better as another tag? + return InteractiveTag.GIVE_ITEM_TO_ALLAY; + } else if (!this.hand.isValid() && !itemInHand.isEmpty()) { return InteractiveTag.GIVE_ITEM_TO_ALLAY; } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { // Seems like there isn't a good tag for this yet @@ -57,7 +72,10 @@ public class AllayEntity extends MobEntity { @Nonnull @Override protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { - if (!this.hand.isValid() && !itemInHand.isEmpty()) { + if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) { + //TOCHECK sound + return InteractionResult.SUCCESS; + } else if (!this.hand.isValid() && !itemInHand.isEmpty()) { //TODO play sound? return InteractionResult.SUCCESS; } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { @@ -67,4 +85,8 @@ public class AllayEntity extends MobEntity { return super.mobInteract(hand, itemInHand); } } + + private boolean isDuplicationItem(GeyserItemStack itemStack) { + return itemStack.getJavaId() == session.getItemMappings().getStoredItems().amethystShard(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 8f9eb415f..b50a9f7d5 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -38,6 +38,7 @@ import java.util.Map; @Getter @Accessors(fluent = true) public class StoredItemMappings { + private final int amethystShard; private final ItemMapping bamboo; private final ItemMapping banner; private final ItemMapping barrier; @@ -71,6 +72,7 @@ public class StoredItemMappings { private final ItemMapping writableBook; public StoredItemMappings(Map itemMappings) { + this.amethystShard = load(itemMappings, "amethyst_shard").getJavaId(); this.bamboo = load(itemMappings, "bamboo"); this.banner = load(itemMappings, "white_banner"); // As of 1.17.10, all banners have the same Bedrock ID this.barrier = load(itemMappings, "barrier"); From d826949b014b26d39a7d00fe1d7614d16b49adbf Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 28 Jul 2022 18:09:35 -0400 Subject: [PATCH 108/290] Indicate support for Bedrock 1.19.11 --- README.md | 2 +- .../java/org/geysermc/geyser/network/MinecraftProtocol.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 796170dfd..62db2d60a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.10 and Minecraft Java 1.19.0. +### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.10/1.19.11 and Minecraft Java 1.19.0. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 4d8ef680c..391bff65f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -61,7 +61,9 @@ public final class MinecraftProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v527.V527_CODEC.toBuilder() .minecraftVersion("1.19.0/1.19.2") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.10/1.19.11") + .build()); } /** 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 109/290] 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 ab5e5a661d61ee1b77f38b99d32ee68ae1d601ef Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 1 Aug 2022 00:37:17 -0400 Subject: [PATCH 110/290] Update wording on `saved-user-logins` --- core/src/main/resources/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index d1a956187..c331a7e62 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -71,7 +71,7 @@ floodgate-key-file: key.pem # This saves a token that can be reused to authenticate the player later. This does not save emails or passwords, # but you should still be cautious when adding to this list and giving others access to this Geyser instance's files. # Removing a name from this list will delete its cached login information on the next Geyser startup. -# The file for this is in the same folder as this config, named "saved-refresh-tokens.json". +# The file that tokens will be saved in is in the same folder as this config, named "saved-refresh-tokens.json". saved-user-logins: - ThisExampleUsernameShouldBeLongEnoughToNeverBeAnXboxUsername - ThisOtherExampleUsernameShouldAlsoBeLongEnough From 51d93205009c294297f5d0216c072b672ca3814a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 1 Aug 2022 11:01:24 -0400 Subject: [PATCH 111/290] Bungee: Check for potentially outdated proxies --- .../platform/bungeecord/GeyserBungeePlugin.java | 15 +++++++++++++++ core/src/main/resources/languages | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index f35082359..0883c5ff0 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.bungeecord; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.protocol.ProtocolConstants; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserBootstrap; @@ -65,6 +66,20 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public void onEnable() { GeyserLocale.init(this); + // Copied from ViaVersion. + // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 + try { + ProtocolConstants.class.getField("MINECRAFT_1_19_1"); + } catch (NoSuchFieldException e) { + getLogger().warning(" / \\"); + getLogger().warning(" / \\"); + getLogger().warning(" / | \\"); + getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); + getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + getLogger().warning(" / o \\"); + getLogger().warning("/_____________\\"); + } + if (!getDataFolder().exists()) getDataFolder().mkdir(); diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index f073cf2b9..4351fc11d 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit f073cf2b9e62d1a9da45ac23448d59ca71074339 +Subproject commit 4351fc11d5fbd9fecc8334910234cdf8a4bc730b From 6856922f428ed4b3b88acc5e3fd888ac1a906276 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 1 Aug 2022 14:45:03 -0400 Subject: [PATCH 112/290] Don't let players change their own gamemode without permission Fixes #3191 --- .../java/org/geysermc/geyser/session/GeyserSession.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index be3dfc2e3..ecc2b0c86 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1674,6 +1674,13 @@ public class GeyserSession implements GeyserConnection, CommandSender { abilities.add(Ability.INSTABUILD); } + if (commandPermission == CommandPermission.OPERATOR) { + // Fixes a bug? since 1.19.11 where the player can change their gamemode in Bedrock settings and + // a packet is not sent to the server. + // https://github.com/GeyserMC/Geyser/issues/3191 + abilities.add(Ability.OPERATOR_COMMANDS); + } + if (flying || spectator) { if (spectator && !flying) { // We're "flying locked" in this gamemode From 7121051d9aa46df8ce8533c71e0e126c4f189fd3 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 2 Aug 2022 00:25:07 -0400 Subject: [PATCH 113/290] Merge mistake fixes --- .../standalone/GeyserStandaloneBootstrap.java | 2 -- build-logic/src/main/kotlin/Versions.kt | 2 +- .../geysermc/geyser/command/CommandManager.java | 0 .../geyser/command/GeyserCommandManager.java | 1 + .../command/defaults/ConnectionTestCommand.java | 14 +++++++------- .../protocol/java/JavaLoginTranslator.java | 2 -- pom.xml | 0 7 files changed, 9 insertions(+), 12 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/command/CommandManager.java delete mode 100644 pom.xml diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 523917ab3..052a41439 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -52,8 +52,6 @@ import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.LoopbackUtil; -import org.geysermc.geyser.platform.standalone.command.GeyserCommandManager; -import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import java.io.File; import java.io.IOException; diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 27f7bcaf5..b02f3b02c 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -35,7 +35,7 @@ object Versions { // See comment in settings.gradle.kts const val raknetVersion = "1.6.28-SNAPSHOT" const val mcauthlibVersion = "d9d773e" - const val mcprotocollibversion = "54fc9f0" + const val mcprotocollibversion = "9f78bd5" const val packetlibVersion = "3.0" const val adventureVersion = "4.9.3" const val eventVersion = "3.0.0" diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java index 4fd5ba411..cb3cf6eee 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java @@ -66,6 +66,7 @@ public abstract class GeyserCommandManager extends CommandManager { registerBuiltInCommand(new StatisticsCommand(geyser, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); registerBuiltInCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); registerBuiltInCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); + registerBuiltInCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); if (GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE) { registerBuiltInCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java index 576d17128..95c115769 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.command.defaults; import com.fasterxml.jackson.databind.JsonNode; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoopbackUtil; @@ -47,10 +47,10 @@ public class ConnectionTestCommand extends GeyserCommand { } @Override - public void execute(@Nullable GeyserSession session, CommandSender sender, String[] args) { + public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { // Only allow the console to create dumps on Geyser Standalone if (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE) { - sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); return; } @@ -69,13 +69,13 @@ public class ConnectionTestCommand extends GeyserCommand { } // Issue: do the ports not line up? - if (port != geyser.getConfig().getBedrock().getPort()) { + if (port != geyser.getConfig().getBedrock().port()) { sender.sendMessage("The port you supplied (" + port + ") does not match the port supplied in Geyser's configuration (" - + geyser.getConfig().getBedrock().getPort() + "). You can change it under `bedrock` `port`."); + + geyser.getConfig().getBedrock().port() + "). You can change it under `bedrock` `port`."); } // Issue: is the `bedrock` `address` in the config different? - if (!geyser.getConfig().getBedrock().getAddress().equals("0.0.0.0")) { + if (!geyser.getConfig().getBedrock().address().equals("0.0.0.0")) { sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional."); } @@ -129,7 +129,7 @@ public class ConnectionTestCommand extends GeyserCommand { }); } - private void sendLinks(CommandSender sender) { + private void sendLinks(GeyserCommandSource sender) { sender.sendMessage("If you still have issues, check to see if your hosting provider has a specific setup: " + "https://wiki.geysermc.org/geyser/supported-hosting-providers/" + ", see this page: " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/" + ", or contact us on our Discord: " + "https://discord.gg/geysermc"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 0adb46c45..6aa613b24 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -40,8 +40,6 @@ import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatTypeEntry; -import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; diff --git a/pom.xml b/pom.xml deleted file mode 100644 index e69de29bb..000000000 From 17f3deb8df94f4e22403e176096c112791f06874 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 2 Aug 2022 01:11:17 -0400 Subject: [PATCH 114/290] try to reset languages --- core/src/main/resources/languages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 615694055..d92904027 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 615694055b1bc7ffba5771dd931ef76b453d16a2 +Subproject commit d92904027061856248ece8382face369e9cc5d67 From a5dc70a3b56bd84974f6bb0cca0fcca438d089c9 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 2 Aug 2022 23:22:08 -0400 Subject: [PATCH 115/290] Refactor extension description --- .../api/extension/ExtensionDescription.java | 26 ++++++- .../extension/GeyserExtensionDescription.java | 76 ++++++++++++------- .../extension/GeyserExtensionLoader.java | 35 +++------ 3 files changed, 82 insertions(+), 55 deletions(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index e77411144..3969bb65f 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -50,13 +50,35 @@ public interface ExtensionDescription { @NonNull String main(); + /** + * Gets the extension's major api version + * + * @return the extension's major api version + */ + int majorApiVersion(); + + /** + * Gets the extension's minor api version + * + * @return the extension's minor api version + */ + int minorApiVersion(); + + /** + * Gets the extension's patch api version + * + * @return the extension's patch api version + */ + int patchApiVersion(); + /** * Gets the extension's api version * * @return the extension's api version */ - @NonNull - String apiVersion(); + default String apiVersion() { + return majorApiVersion() + "." + minorApiVersion() + "." + patchApiVersion(); + } /** * Gets the extension's description diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index eaf29a819..797b43a81 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -25,53 +25,75 @@ package org.geysermc.geyser.extension; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; -import org.yaml.snakeyaml.DumperOptions; +import org.geysermc.geyser.text.GeyserLocale; import org.yaml.snakeyaml.Yaml; import java.io.Reader; import java.util.*; +import java.util.regex.Pattern; -public record GeyserExtensionDescription(String name, String main, String apiVersion, String version, List authors) implements ExtensionDescription { +public record GeyserExtensionDescription(@NonNull String name, + @NonNull String main, + int majorApiVersion, + int minorApiVersion, + int patchApiVersion, + @NonNull String version, + @NonNull List authors) implements ExtensionDescription { + + private static final Yaml YAML = new Yaml(); + public static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_.-]*$"); + public static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); + + @NonNull @SuppressWarnings("unchecked") public static GeyserExtensionDescription fromYaml(Reader reader) throws InvalidDescriptionException { - DumperOptions dumperOptions = new DumperOptions(); - dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - - Yaml yaml = new Yaml(dumperOptions); - Map yamlMap = yaml.loadAs(reader, LinkedHashMap.class); - - String name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); - if (name.isBlank()) { - throw new InvalidDescriptionException("Invalid extension name, cannot be empty"); + Map map; + try { + map = YAML.loadAs(reader, HashMap.class); + } catch (Exception e) { + throw new InvalidDescriptionException(e); } - name = name.replace(" ", "_"); - String version = String.valueOf(yamlMap.get("version")); - String main = (String) yamlMap.get("main"); - String apiVersion; - - Object api = yamlMap.get("api"); - if (api instanceof String) { - apiVersion = (String) api; - } else { - throw new InvalidDescriptionException("Invalid api version format, should be a string: major.minor.patch"); + String name = require(map, "name"); + if (!NAME_PATTERN.matcher(name).matches()) { + throw new InvalidDescriptionException("Invalid extension name, must match: " + NAME_PATTERN.pattern()); } + String version = String.valueOf(map.get("version")); + String main = require(map, "main"); + + String apiVersion = require(map, "api"); + if (!API_VERSION_PATTERN.matcher(apiVersion).matches()) { + throw new InvalidDescriptionException(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion)); + } + String[] api = apiVersion.split("\\."); + int majorApi = Integer.parseUnsignedInt(api[0]); + int minorApi = Integer.parseUnsignedInt(api[1]); + int patchApi = Integer.parseUnsignedInt(api[2]); List authors = new ArrayList<>(); - if (yamlMap.containsKey("author")) { - authors.add((String) yamlMap.get("author")); + if (map.containsKey("author")) { + authors.add(String.valueOf(map.get("author"))); } - - if (yamlMap.containsKey("authors")) { + if (map.containsKey("authors")) { try { - authors.addAll((Collection) yamlMap.get("authors")); + authors.addAll((Collection) map.get("authors")); } catch (Exception e) { throw new InvalidDescriptionException("Invalid authors format, should be a list of strings", e); } } - return new GeyserExtensionDescription(name, main, apiVersion, version, authors); + return new GeyserExtensionDescription(name, main, majorApi, minorApi, patchApi, version, authors); + } + + @NonNull + private static String require(Map desc, String key) throws InvalidDescriptionException { + Object value = desc.get(key); + if (value instanceof String) { + return (String) value; + } + throw new InvalidDescriptionException("Extension description is missing string property '" + key + "'"); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 55f018ddb..fcb718dec 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -39,25 +39,24 @@ import org.geysermc.geyser.extension.event.GeyserExtensionEventBus; import org.geysermc.geyser.text.GeyserLocale; import java.io.IOException; +import java.io.Reader; import java.nio.file.*; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.regex.Pattern; import java.util.stream.Stream; @RequiredArgsConstructor public class GeyserExtensionLoader extends ExtensionLoader { private static final Path EXTENSION_DIRECTORY = Paths.get("extensions"); - private static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); private static final Pattern[] EXTENSION_FILTERS = new Pattern[] { Pattern.compile("^.+\\.jar$") }; private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); private final Map classLoaders = new HashMap<>(); private final Map extensionContainers = new HashMap<>(); - public GeyserExtensionContainer loadExtension(Path path, GeyserExtensionDescription description) throws InvalidExtensionException, InvalidDescriptionException { + public GeyserExtensionContainer loadExtension(Path path, GeyserExtensionDescription description) throws InvalidExtensionException { if (path == null) { throw new InvalidExtensionException("Path is null"); } @@ -94,7 +93,9 @@ public class GeyserExtensionLoader extends ExtensionLoader { Map environment = new HashMap<>(); try (FileSystem fileSystem = FileSystems.newFileSystem(path, environment, null)) { Path extensionYml = fileSystem.getPath("extension.yml"); - return GeyserExtensionDescription.fromYaml(Files.newBufferedReader(extensionYml)); + try (Reader reader = Files.newBufferedReader(extensionYml)) { + return GeyserExtensionDescription.fromYaml(reader); + } } catch (IOException ex) { throw new InvalidDescriptionException("Failed to load extension description for " + path, ex); } @@ -149,9 +150,6 @@ public class GeyserExtensionLoader extends ExtensionLoader { try { GeyserExtensionDescription description = this.extensionDescription(path); - if (description == null) { - return; - } String name = description.name(); if (extensions.containsKey(name) || extensionManager.extension(name) != null) { @@ -159,30 +157,15 @@ public class GeyserExtensionLoader extends ExtensionLoader { return; } - int majorVersion = Geyser.api().majorApiVersion(); - int minorVersion = Geyser.api().minorApiVersion(); - - try { - // Check the format: majorVersion.minorVersion.patch - if (!API_VERSION_PATTERN.matcher(description.apiVersion()).matches()) { - throw new IllegalArgumentException(); - } - } catch (NullPointerException | IllegalArgumentException e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, majorVersion + "." + minorVersion)); - return; - } - - String[] versionArray = description.apiVersion().split("\\."); - // Completely different API version - if (Integer.parseInt(versionArray[0]) != majorVersion) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, majorVersion + "." + minorVersion)); + if (description.majorApiVersion() != Geyser.api().majorApiVersion()) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); return; } // If the extension requires new API features, being backwards compatible - if (Integer.parseInt(versionArray[1]) > minorVersion) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, majorVersion + "." + minorVersion)); + if (description.minorApiVersion() > Geyser.api().minorApiVersion()) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); return; } From aa7d0f4a57b2b93acc69aab0e2f1704c2e0e188f Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:20:27 -0400 Subject: [PATCH 116/290] Use class for reading extension.yml --- .../extension/GeyserExtensionDescription.java | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 797b43a81..8fab4e338 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -25,14 +25,18 @@ package org.geysermc.geyser.extension; +import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.text.GeyserLocale; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor; import java.io.Reader; import java.util.*; +import java.util.function.Supplier; import java.util.regex.Pattern; public record GeyserExtensionDescription(@NonNull String name, @@ -43,28 +47,27 @@ public record GeyserExtensionDescription(@NonNull String name, @NonNull String version, @NonNull List authors) implements ExtensionDescription { - private static final Yaml YAML = new Yaml(); + private static final Yaml YAML = new Yaml(new CustomClassLoaderConstructor(Source.class.getClassLoader())); public static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_.-]*$"); public static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); @NonNull - @SuppressWarnings("unchecked") public static GeyserExtensionDescription fromYaml(Reader reader) throws InvalidDescriptionException { - Map map; + Source source; try { - map = YAML.loadAs(reader, HashMap.class); + source = YAML.loadAs(reader, Source.class); } catch (Exception e) { throw new InvalidDescriptionException(e); } - String name = require(map, "name"); + String name = require(source::getName, "name"); if (!NAME_PATTERN.matcher(name).matches()) { throw new InvalidDescriptionException("Invalid extension name, must match: " + NAME_PATTERN.pattern()); } - String version = String.valueOf(map.get("version")); - String main = require(map, "main"); + String version = String.valueOf(source.version); + String main = require(source::getMain, "main"); - String apiVersion = require(map, "api"); + String apiVersion = require(source::getApi, "api"); if (!API_VERSION_PATTERN.matcher(apiVersion).matches()) { throw new InvalidDescriptionException(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion)); } @@ -74,26 +77,33 @@ public record GeyserExtensionDescription(@NonNull String name, int patchApi = Integer.parseUnsignedInt(api[2]); List authors = new ArrayList<>(); - if (map.containsKey("author")) { - authors.add(String.valueOf(map.get("author"))); + if (source.author != null) { + authors.add(source.author); } - if (map.containsKey("authors")) { - try { - authors.addAll((Collection) map.get("authors")); - } catch (Exception e) { - throw new InvalidDescriptionException("Invalid authors format, should be a list of strings", e); - } + if (source.authors != null) { + authors.addAll(source.authors); } return new GeyserExtensionDescription(name, main, majorApi, minorApi, patchApi, version, authors); } @NonNull - private static String require(Map desc, String key) throws InvalidDescriptionException { - Object value = desc.get(key); - if (value instanceof String) { - return (String) value; + private static String require(Supplier supplier, String name) throws InvalidDescriptionException { + String value = supplier.get(); + if (value == null) { + throw new InvalidDescriptionException("Extension description is missing string property '" + name + "'"); } - throw new InvalidDescriptionException("Extension description is missing string property '" + key + "'"); + return value; + } + + @Getter + @Setter + public static class Source { + String name; + String main; + String api; + String version; + String author; + List authors; } } From 36ef23b24e50590fef2b63b52478a86ea2008763 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:30:22 -0400 Subject: [PATCH 117/290] Don't allow empty extension name --- .../geysermc/geyser/extension/GeyserExtensionDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 8fab4e338..010c1430c 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -48,7 +48,7 @@ public record GeyserExtensionDescription(@NonNull String name, @NonNull List authors) implements ExtensionDescription { private static final Yaml YAML = new Yaml(new CustomClassLoaderConstructor(Source.class.getClassLoader())); - public static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_.-]*$"); + public static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_.-]+$"); public static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); @NonNull From 67e3bf1f8dd864fa68c0cd672212145e03a030ba Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 4 Aug 2022 17:55:12 -0400 Subject: [PATCH 118/290] Move extensions folder to Geyser's config folder (#3202) * Move extensions folder to Geyser's config folder * Move directory field --- .../geysermc/geyser/extension/GeyserExtensionLoader.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 55f018ddb..d317bc013 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -43,19 +43,18 @@ import java.nio.file.*; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.regex.Pattern; import java.util.stream.Stream; @RequiredArgsConstructor public class GeyserExtensionLoader extends ExtensionLoader { - private static final Path EXTENSION_DIRECTORY = Paths.get("extensions"); private static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); private static final Pattern[] EXTENSION_FILTERS = new Pattern[] { Pattern.compile("^.+\\.jar$") }; private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); private final Map classLoaders = new HashMap<>(); private final Map extensionContainers = new HashMap<>(); + private final Path extensionsDirectory = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("extensions"); public GeyserExtensionContainer loadExtension(Path path, GeyserExtensionDescription description) throws InvalidExtensionException, InvalidDescriptionException { if (path == null) { @@ -127,15 +126,15 @@ public class GeyserExtensionLoader extends ExtensionLoader { @Override protected void loadAllExtensions(@NonNull ExtensionManager extensionManager) { try { - if (Files.notExists(EXTENSION_DIRECTORY)) { - Files.createDirectory(EXTENSION_DIRECTORY); + if (Files.notExists(extensionsDirectory)) { + Files.createDirectory(extensionsDirectory); } Map extensions = new LinkedHashMap<>(); Map loadedExtensions = new LinkedHashMap<>(); Pattern[] extensionFilters = this.extensionFilters(); - try (Stream entries = Files.walk(EXTENSION_DIRECTORY)) { + try (Stream entries = Files.walk(extensionsDirectory)) { entries.forEach(path -> { if (Files.isDirectory(path)) { return; From 3c27273eac3a13b051523cb004f4ca521885576e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 5 Aug 2022 11:29:47 -0400 Subject: [PATCH 119/290] Indicate support for Java 1.19.2 --- README.md | 2 +- .../java/org/geysermc/geyser/network/MinecraftProtocol.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 62db2d60a..49aba79ac 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.10/1.19.11 and Minecraft Java 1.19.0. +### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.10/1.19.11 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 391bff65f..3d5bc01ab 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -33,7 +33,6 @@ import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.StringJoiner; @@ -101,7 +100,7 @@ public final class MinecraftProtocol { * @return the supported Minecraft: Java Edition version names */ public static List getJavaVersions() { - return Collections.singletonList(DEFAULT_JAVA_CODEC.getMinecraftVersion()); + return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion(), "1.19.2"); } /** From f74713c0edca0f94eb90c26c7dfd177ff8623381 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 7 Aug 2022 12:09:54 -0400 Subject: [PATCH 120/290] Initial support for 1.19.20 Bedrock --- core/pom.xml | 4 +-- .../geyser/network/MinecraftProtocol.java | 2 ++ .../populator/BlockRegistryPopulator.java | 31 ++++++++++-------- .../geyser/session/GeyserSession.java | 2 ++ .../bedrock/block_palette.1_19_20.nbt | Bin 0 -> 55132 bytes core/src/main/resources/mappings | 2 +- 6 files changed, 24 insertions(+), 17 deletions(-) create mode 100644 core/src/main/resources/bedrock/block_palette.1_19_20.nbt diff --git a/core/pom.xml b/core/pom.xml index 8977854cb..88bde3360 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -128,8 +128,8 @@ com.github.CloudburstMC.Protocol - bedrock-v534 - a78a64b + bedrock-v544 + 92d9854 compile diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 3d5bc01ab..e0a06b5e3 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; +import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -63,6 +64,7 @@ public final class MinecraftProtocol { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.10/1.19.11") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); } /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 53c3e2310..ce8f05ed8 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; +import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -56,17 +57,7 @@ import java.util.zip.GZIPInputStream; /** * Populates the block registries. */ -public class BlockRegistryPopulator { - private static final ImmutableMap, BiFunction> BLOCK_MAPPERS; - private static final BiFunction EMPTY_MAPPER = (bedrockIdentifier, statesBuilder) -> null; - - static { - ImmutableMap.Builder, BiFunction> stateMapperBuilder = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_19_0", Bedrock_v527.V527_CODEC.getProtocolVersion()), EMPTY_MAPPER); - - BLOCK_MAPPERS = stateMapperBuilder.build(); - } - +public final class BlockRegistryPopulator { /** * Stores the raw blocks JSON until it is no longer needed. */ @@ -80,7 +71,17 @@ public class BlockRegistryPopulator { } private static void registerBedrockBlocks() { - for (Map.Entry, BiFunction> palette : BLOCK_MAPPERS.entrySet()) { + BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; + ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() + .put(ObjectIntPair.of("1_19_0", Bedrock_v527.V527_CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> { + if (bedrockIdentifier.equals("minecraft:muddy_mangrove_roots")) { + statesBuilder.remove("pillar_axis"); + } + return null; + }) + .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper).build(); + + for (Map.Entry, BiFunction> palette : blockMappers.entrySet()) { NbtList blocksTag; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey().key())); NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) { @@ -95,7 +96,9 @@ public class BlockRegistryPopulator { int stateVersion = -1; for (int i = 0; i < blocksTag.size(); i++) { - NbtMap tag = blocksTag.get(i); + NbtMapBuilder builder = blocksTag.get(i).toBuilder(); + builder.remove("name_hash"); // Quick workaround - was added in 1.19.20 + NbtMap tag = builder.build(); if (blockStateOrderedMap.containsKey(tag)) { throw new AssertionError("Duplicate block states in Bedrock palette: " + tag); } @@ -111,7 +114,7 @@ public class BlockRegistryPopulator { int movingBlockRuntimeId = -1; Iterator> blocksIterator = BLOCKS_JSON.fields(); - BiFunction stateMapper = BLOCK_MAPPERS.getOrDefault(palette.getKey(), EMPTY_MAPPER); + BiFunction stateMapper = blockMappers.getOrDefault(palette.getKey(), emptyMapper); int[] javaToBedrockBlocks = new int[BLOCKS_JSON.size()]; diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index ecc2b0c86..f7c990ac3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1491,6 +1491,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { startGamePacket.setPlayerPropertyData(NbtMap.EMPTY); startGamePacket.setWorldTemplateId(UUID.randomUUID()); + startGamePacket.setChatRestrictionLevel(ChatRestrictionLevel.NONE); + SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings(); settings.setMovementMode(AuthoritativeMovementMode.CLIENT); settings.setRewindHistorySize(0); diff --git a/core/src/main/resources/bedrock/block_palette.1_19_20.nbt b/core/src/main/resources/bedrock/block_palette.1_19_20.nbt new file mode 100644 index 0000000000000000000000000000000000000000..75d84b6a767aed381f7afd63fe0853b6e9c2a379 GIT binary patch literal 55132 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

N!K?VWkIdC++V5CX^Dc;QTi}}9T=lerttP4d#b zb@t-=s{f05Iog>R1Xnsx(kBjuLM1(5y> z0`qrk9IcJ3+X^bauWCFyv*Q|9W3$obUsIWO6GmRVc&~n)wYRmd-o(d};}KuUSvr_< zo?aev3X z@?O();jB+SQW0T>*lBV|#ERayqI6_69C>_wlrJ2B*~T_zyVA)LGk_H(QOpU&q^aPc zgIaaCmZOZhK#J7-|J%$y!aAdFvA{53{F3{;m8ORSjLa;Yd0HZz1AiZcz$hmDM`Awa zn{-Jc@GLf5N>k!DrZJRc<1Di;v;f9x^n#gwRmlZFpeT_!p?pUzZBF&mka*oEPSx^3 z%4?=6**e=DBe_)h1LL%53-I%rtiTCBzA~3~2^a{$*?Ucsrhl{dEK;Yra)wkk6D;f` zTGJY90D-s%PIKUCK4_XQuZ!y-86EpCGadf7nMeO+rrdvH=H-8HrUaJBX=-j)FB5`v zQIKt9Qv^8%>R&&^`QnSxu&Fp5}1Li)>l8YTv9@r0ZJG;P5AP^?cZ9k;c1oTm@6?}pJ zIzgZEZyyB>sSSb4mB%**{(%8@LZt)k{ASHq_V=ML1%3ZzX666fOlaPgjik=}JWRvd z?+W4I@6-2dtjAl;)4`RdKUK2&n$d0piAM?yg}^}O7o^ZzRG4s>o2^<>lpu37+`n>F zuqyr-85+24$wO9Q)v)eIJ?^yZpk^agqM~c~^5}C*Mt3)pwabX8U4Nd__3uP7Z->8O zKwPFCId^Pi0`xyHR#^k9M&`)F7Hs@kBQ5%K94Lx^#YN~G4y%nvc$ur@K>|$EG zAKNdmu)?UQPP2YS zU=&B@Ra9zNLe2ROO+n^5G1=p$??b{bYTsXUWu8g(qoWFqbDVo8GMsqN@FsYKVTl z8lK9|?b-#)Zwz9VH%lp}R{E-1_D8c(moRQtfWn;P2kME5d;EbqxtsOQ1YUdN?gTlp vX!0f2XX*s~rfjqL4L=}#m+!XCdF;?V!=^KE4f37S^XE`*=^ZZ(bcp{2Ge*tJ literal 0 HcmV?d00001 diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 012789123..2c68dab9d 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 0127891232742209b8470298dfd997249c506320 +Subproject commit 2c68dab9d751f78b2f5b0298da5e338ad6bc07ca From ef81bdeb6bb6a70a644055b9e32b3bef4dc6cd46 Mon Sep 17 00:00:00 2001 From: 7man7LMYT <67489949+7man7LMYT@users.noreply.github.com> Date: Tue, 9 Aug 2022 13:52:53 -0700 Subject: [PATCH 121/290] Update items to 1.19.20 (#3215) * Update to 1.19.20 * Add 1.19.20 mapping * Revert biome changes --- .../populator/ItemRegistryPopulator.java | 2 + .../bedrock/creative_items.1_19_20.json | 5440 +++++++++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 7762 -> 7762 bytes .../bedrock/runtime_item_states.1_19_20.json | 4530 ++++++++++++++ 4 files changed, 9972 insertions(+) create mode 100644 core/src/main/resources/bedrock/creative_items.1_19_20.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_20.json diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 5dc60b44b..ad1020e9b 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -37,6 +37,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; +import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -68,6 +69,7 @@ public class ItemRegistryPopulator { paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.V527_CODEC.getProtocolVersion(), Collections.singletonMap("minecraft:trader_llama_spawn_egg", "minecraft:llama_spawn_egg"))); paletteVersions.put("1_19_10", new PaletteVersion(Bedrock_v534.V534_CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.V544_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/resources/bedrock/creative_items.1_19_20.json b/core/src/main/resources/bedrock/creative_items.1_19_20.json new file mode 100644 index 000000000..98d9e007a --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_19_20.json @@ -0,0 +1,5440 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6073 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6074 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6075 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6076 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6077 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6078 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 949 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 4852 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 922 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1184 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1185 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1186 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1187 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1188 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1189 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1196 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1191 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1192 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1190 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1193 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1197 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1194 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1195 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 3932 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 6726 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 973 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 8084 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 5073 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 7819 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 431 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 732 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7366 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7367 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7368 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7369 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7370 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7371 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 6635 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 4292 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 7998 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 5855 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6586 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 3779 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5367 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 7588 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 4175 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 4627 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 4663 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 5401 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 635 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 3710 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 4094 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 273 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 128 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 7005 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 6969 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 6202 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 5065 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 4597 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 933 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5885 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 3589 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 3629 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 5352 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 5548 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 3539 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 4152 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4393 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6716 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 5310 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 7030 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 6532 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 106 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6604 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 6384 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 4769 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 7702 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 7757 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 7265 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 7432 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 206 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 6282 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 3720 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 7021 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 4299 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 4479 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 4606 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4589 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 4307 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 353 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 395 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 3904 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 6169 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 5842 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4655 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 294 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 7424 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 5524 + }, + { + "id" : "minecraft:wooden_door" + }, + { + "id" : "minecraft:spruce_door" + }, + { + "id" : "minecraft:birch_door" + }, + { + "id" : "minecraft:jungle_door" + }, + { + "id" : "minecraft:acacia_door" + }, + { + "id" : "minecraft:dark_oak_door" + }, + { + "id" : "minecraft:mangrove_door" + }, + { + "id" : "minecraft:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 229 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 6554 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 6652 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 5383 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 5591 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 7504 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 4487 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 321 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 4335 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 4735 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 4803 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 6166 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1135 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1143 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1142 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1150 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1147 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1149 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1136 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1139 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1140 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1148 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1144 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1138 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1146 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1145 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1137 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1141 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 5977 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4854 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4862 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4861 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4869 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4866 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4868 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4855 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4858 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4859 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4867 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4857 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4864 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4856 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4860 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 8264 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 3573 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4272 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5824 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4275 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5272 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5273 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5274 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5275 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5276 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5277 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1151 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5822 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4273 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5825 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5796 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5790 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5826 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5807 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5812 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5813 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5810 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5809 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5808 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4279 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5797 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5806 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4278 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5823 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5791 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5792 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5793 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5794 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 5902 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 6486 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 912 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6020 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 4194 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 5237 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 6602 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 6055 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5284 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7817 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 249 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 6547 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 710 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 7312 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4293 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 3718 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 3912 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 4767 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 7251 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 4554 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6353 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6549 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6551 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6552 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 281 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6089 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 4682 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 7216 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4588 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 5064 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4583 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 4162 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 5466 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 5366 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 5236 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 3617 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 6672 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 4584 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3657 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3658 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6582 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6583 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6584 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6585 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 5400 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 7981 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 291 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 8263 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 4653 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 595 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 8248 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 3555 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7736 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 696 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 709 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7544 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 4691 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 6168 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7199 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5480 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7295 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 3811 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 4853 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1161 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 272 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 4288 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 8262 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 5271 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 363 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3700 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3701 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6087 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6088 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 4235 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 4478 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 697 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 4236 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 7274 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 146 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 3777 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 8261 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3460 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3468 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3467 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3475 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3472 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3474 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3461 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3464 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3465 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3473 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3469 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3463 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3471 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3470 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3462 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3466 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 951 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 959 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 958 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 966 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 963 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 965 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 952 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 955 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 956 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 964 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 960 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 954 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 962 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 961 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 953 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 957 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6266 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6274 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6273 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6281 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6278 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6267 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6270 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6271 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6279 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6275 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6269 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6277 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6276 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6268 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6272 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 662 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 670 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 669 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 677 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 674 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 676 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 663 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 666 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 667 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 675 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 671 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 665 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 673 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 672 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 664 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 668 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 7126 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 643 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6178 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6186 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6185 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6193 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6190 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6192 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6182 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6183 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6191 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6187 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6188 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6180 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6184 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 5575 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 3533 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 8255 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 5836 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 3549 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 4169 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 1153 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 915 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 223 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 6612 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 5360 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 5473 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 5467 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 7013 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 967 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 6541 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7718 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 283 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 6891 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 4295 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 5907 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 5063 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 4191 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 4351 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 24 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 1159 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 5832 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5753 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5754 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 3914 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 6977 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 8083 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 4652 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 3685 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 6686 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 655 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 4692 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 914 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 4363 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 7701 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 4291 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 4289 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 3556 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 7349 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 4503 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 27 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 6109 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 7275 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 6108 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 8040 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 7264 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 6618 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 6352 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 7198 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 105 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 8289 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 656 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 658 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 660 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 7587 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 253 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 657 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 659 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 661 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 3684 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 7756 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4197 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4198 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 6988 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6674 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 7545 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6675 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 6290 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6676 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 5974 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6677 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 644 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3832 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 5850 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3833 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 216 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 350 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 8286 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 5899 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 6950 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 6488 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 7402 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3476 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3482 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3477 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3483 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3478 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3484 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3479 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3485 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3480 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3486 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3481 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3487 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 4163 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 4231 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 4296 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 6501 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 5904 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 5581 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6092 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6093 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6094 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6095 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4355 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4356 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 6668 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 7712 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 6341 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 714 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 715 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 716 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 717 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 718 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 719 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 6978 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 5756 + }, + { + "id" : "minecraft:wheat_seeds" + }, + { + "id" : "minecraft:pumpkin_seeds" + }, + { + "id" : "minecraft:melon_seeds" + }, + { + "id" : "minecraft:beetroot_seeds" + }, + { + "id" : "minecraft:wheat" + }, + { + "id" : "minecraft:beetroot" + }, + { + "id" : "minecraft:potato" + }, + { + "id" : "minecraft:poisonous_potato" + }, + { + "id" : "minecraft:carrot" + }, + { + "id" : "minecraft:golden_carrot" + }, + { + "id" : "minecraft:apple" + }, + { + "id" : "minecraft:golden_apple" + }, + { + "id" : "minecraft:enchanted_golden_apple" + }, + { + "id" : "minecraft:melon_block", + "blockRuntimeId" : 394 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 4579 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 7380 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 6687 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 931 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5457 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 930 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5456 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6494 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6492 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6493 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6491 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6495 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6499 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6497 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6498 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6496 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6500 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4618 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4616 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4617 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4615 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4619 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 69 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 67 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 68 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 66 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 70 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 246 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 7575 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 4364 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 302 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3618 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3619 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3620 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3621 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3622 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3623 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3624 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3625 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3626 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3627 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3628 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5454 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5455 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5458 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5459 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 6167 + }, + { + "id" : "minecraft:white_dye" + }, + { + "id" : "minecraft:light_gray_dye" + }, + { + "id" : "minecraft:gray_dye" + }, + { + "id" : "minecraft:black_dye" + }, + { + "id" : "minecraft:brown_dye" + }, + { + "id" : "minecraft:red_dye" + }, + { + "id" : "minecraft:orange_dye" + }, + { + "id" : "minecraft:yellow_dye" + }, + { + "id" : "minecraft:lime_dye" + }, + { + "id" : "minecraft:green_dye" + }, + { + "id" : "minecraft:cyan_dye" + }, + { + "id" : "minecraft:light_blue_dye" + }, + { + "id" : "minecraft:blue_dye" + }, + { + "id" : "minecraft:purple_dye" + }, + { + "id" : "minecraft:magenta_dye" + }, + { + "id" : "minecraft:pink_dye" + }, + { + "id" : "minecraft:ink_sac" + }, + { + "id" : "minecraft:glow_ink_sac" + }, + { + "id" : "minecraft:cocoa_beans" + }, + { + "id" : "minecraft:lapis_lazuli" + }, + { + "id" : "minecraft:bone_meal" + }, + { + "id" : "minecraft:vine", + "blockRuntimeId" : 896 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 5481 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 5693 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 1160 + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 4679 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 3686 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 4196 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 6691 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 282 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 7029 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 155 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 7418 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 895 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 286 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 6540 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 5399 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 205 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 6177 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 345 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 5982 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 4322 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 7314 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 6890 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 5479 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 5686 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 290 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 7004 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 7812 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 4730 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 4378 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 304 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 349 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 215 + }, + { + "id" : "minecraft:chicken" + }, + { + "id" : "minecraft:porkchop" + }, + { + "id" : "minecraft:beef" + }, + { + "id" : "minecraft:mutton" + }, + { + "id" : "minecraft:rabbit" + }, + { + "id" : "minecraft:cod" + }, + { + "id" : "minecraft:salmon" + }, + { + "id" : "minecraft:tropical_fish" + }, + { + "id" : "minecraft:pufferfish" + }, + { + "id" : "minecraft:brown_mushroom", + "blockRuntimeId" : 3548 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 4587 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 7755 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 287 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7364 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 3613 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7365 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7350 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 6715 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 403 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4146 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4147 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4148 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4149 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4150 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4151 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 4643 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 7273 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 7999 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 4401 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 6437 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 6483 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 3512 + }, + { + "id" : "minecraft:chicken_spawn_egg" + }, + { + "id" : "minecraft:bee_spawn_egg" + }, + { + "id" : "minecraft:cow_spawn_egg" + }, + { + "id" : "minecraft:pig_spawn_egg" + }, + { + "id" : "minecraft:sheep_spawn_egg" + }, + { + "id" : "minecraft:wolf_spawn_egg" + }, + { + "id" : "minecraft:polar_bear_spawn_egg" + }, + { + "id" : "minecraft:ocelot_spawn_egg" + }, + { + "id" : "minecraft:cat_spawn_egg" + }, + { + "id" : "minecraft:mooshroom_spawn_egg" + }, + { + "id" : "minecraft:bat_spawn_egg" + }, + { + "id" : "minecraft:parrot_spawn_egg" + }, + { + "id" : "minecraft:rabbit_spawn_egg" + }, + { + "id" : "minecraft:llama_spawn_egg" + }, + { + "id" : "minecraft:horse_spawn_egg" + }, + { + "id" : "minecraft:donkey_spawn_egg" + }, + { + "id" : "minecraft:mule_spawn_egg" + }, + { + "id" : "minecraft:skeleton_horse_spawn_egg" + }, + { + "id" : "minecraft:zombie_horse_spawn_egg" + }, + { + "id" : "minecraft:tropical_fish_spawn_egg" + }, + { + "id" : "minecraft:cod_spawn_egg" + }, + { + "id" : "minecraft:pufferfish_spawn_egg" + }, + { + "id" : "minecraft:salmon_spawn_egg" + }, + { + "id" : "minecraft:dolphin_spawn_egg" + }, + { + "id" : "minecraft:turtle_spawn_egg" + }, + { + "id" : "minecraft:panda_spawn_egg" + }, + { + "id" : "minecraft:fox_spawn_egg" + }, + { + "id" : "minecraft:creeper_spawn_egg" + }, + { + "id" : "minecraft:enderman_spawn_egg" + }, + { + "id" : "minecraft:silverfish_spawn_egg" + }, + { + "id" : "minecraft:skeleton_spawn_egg" + }, + { + "id" : "minecraft:wither_skeleton_spawn_egg" + }, + { + "id" : "minecraft:stray_spawn_egg" + }, + { + "id" : "minecraft:slime_spawn_egg" + }, + { + "id" : "minecraft:spider_spawn_egg" + }, + { + "id" : "minecraft:zombie_spawn_egg" + }, + { + "id" : "minecraft:zombie_pigman_spawn_egg" + }, + { + "id" : "minecraft:husk_spawn_egg" + }, + { + "id" : "minecraft:drowned_spawn_egg" + }, + { + "id" : "minecraft:squid_spawn_egg" + }, + { + "id" : "minecraft:glow_squid_spawn_egg" + }, + { + "id" : "minecraft:cave_spider_spawn_egg" + }, + { + "id" : "minecraft:witch_spawn_egg" + }, + { + "id" : "minecraft:guardian_spawn_egg" + }, + { + "id" : "minecraft:elder_guardian_spawn_egg" + }, + { + "id" : "minecraft:endermite_spawn_egg" + }, + { + "id" : "minecraft:magma_cube_spawn_egg" + }, + { + "id" : "minecraft:strider_spawn_egg" + }, + { + "id" : "minecraft:hoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_spawn_egg" + }, + { + "id" : "minecraft:zoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_brute_spawn_egg" + }, + { + "id" : "minecraft:goat_spawn_egg" + }, + { + "id" : "minecraft:axolotl_spawn_egg" + }, + { + "id" : "minecraft:warden_spawn_egg" + }, + { + "id" : "minecraft:allay_spawn_egg" + }, + { + "id" : "minecraft:frog_spawn_egg" + }, + { + "id" : "minecraft:tadpole_spawn_egg" + }, + { + "id" : "minecraft:trader_llama_spawn_egg" + }, + { + "id" : "minecraft:ghast_spawn_egg" + }, + { + "id" : "minecraft:blaze_spawn_egg" + }, + { + "id" : "minecraft:shulker_spawn_egg" + }, + { + "id" : "minecraft:vindicator_spawn_egg" + }, + { + "id" : "minecraft:evoker_spawn_egg" + }, + { + "id" : "minecraft:vex_spawn_egg" + }, + { + "id" : "minecraft:villager_spawn_egg" + }, + { + "id" : "minecraft:wandering_trader_spawn_egg" + }, + { + "id" : "minecraft:zombie_villager_spawn_egg" + }, + { + "id" : "minecraft:phantom_spawn_egg" + }, + { + "id" : "minecraft:pillager_spawn_egg" + }, + { + "id" : "minecraft:ravager_spawn_egg" + }, + { + "id" : "minecraft:obsidian", + "blockRuntimeId" : 430 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 6724 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 5833 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 7039 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 8011 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 3838 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 4532 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 5507 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 631 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 632 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5239 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5240 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5241 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5242 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5243 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5244 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5245 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5246 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5247 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5248 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 7038 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 7134 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 3615 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 4391 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 5834 + }, + { + "id" : "minecraft:leather_helmet" + }, + { + "id" : "minecraft:chainmail_helmet" + }, + { + "id" : "minecraft:iron_helmet" + }, + { + "id" : "minecraft:golden_helmet" + }, + { + "id" : "minecraft:diamond_helmet" + }, + { + "id" : "minecraft:netherite_helmet" + }, + { + "id" : "minecraft:leather_chestplate" + }, + { + "id" : "minecraft:chainmail_chestplate" + }, + { + "id" : "minecraft:iron_chestplate" + }, + { + "id" : "minecraft:golden_chestplate" + }, + { + "id" : "minecraft:diamond_chestplate" + }, + { + "id" : "minecraft:netherite_chestplate" + }, + { + "id" : "minecraft:leather_leggings" + }, + { + "id" : "minecraft:chainmail_leggings" + }, + { + "id" : "minecraft:iron_leggings" + }, + { + "id" : "minecraft:golden_leggings" + }, + { + "id" : "minecraft:diamond_leggings" + }, + { + "id" : "minecraft:netherite_leggings" + }, + { + "id" : "minecraft:leather_boots" + }, + { + "id" : "minecraft:chainmail_boots" + }, + { + "id" : "minecraft:iron_boots" + }, + { + "id" : "minecraft:golden_boots" + }, + { + "id" : "minecraft:diamond_boots" + }, + { + "id" : "minecraft:netherite_boots" + }, + { + "id" : "minecraft:wooden_sword" + }, + { + "id" : "minecraft:stone_sword" + }, + { + "id" : "minecraft:iron_sword" + }, + { + "id" : "minecraft:golden_sword" + }, + { + "id" : "minecraft:diamond_sword" + }, + { + "id" : "minecraft:netherite_sword" + }, + { + "id" : "minecraft:wooden_axe" + }, + { + "id" : "minecraft:stone_axe" + }, + { + "id" : "minecraft:iron_axe" + }, + { + "id" : "minecraft:golden_axe" + }, + { + "id" : "minecraft:diamond_axe" + }, + { + "id" : "minecraft:netherite_axe" + }, + { + "id" : "minecraft:wooden_pickaxe" + }, + { + "id" : "minecraft:stone_pickaxe" + }, + { + "id" : "minecraft:iron_pickaxe" + }, + { + "id" : "minecraft:golden_pickaxe" + }, + { + "id" : "minecraft:diamond_pickaxe" + }, + { + "id" : "minecraft:netherite_pickaxe" + }, + { + "id" : "minecraft:wooden_shovel" + }, + { + "id" : "minecraft:stone_shovel" + }, + { + "id" : "minecraft:iron_shovel" + }, + { + "id" : "minecraft:golden_shovel" + }, + { + "id" : "minecraft:diamond_shovel" + }, + { + "id" : "minecraft:netherite_shovel" + }, + { + "id" : "minecraft:wooden_hoe" + }, + { + "id" : "minecraft:stone_hoe" + }, + { + "id" : "minecraft:iron_hoe" + }, + { + "id" : "minecraft:golden_hoe" + }, + { + "id" : "minecraft:diamond_hoe" + }, + { + "id" : "minecraft:netherite_hoe" + }, + { + "id" : "minecraft:bow" + }, + { + "id" : "minecraft:crossbow" + }, + { + "id" : "minecraft:arrow" + }, + { + "id" : "minecraft:arrow", + "damage" : 6 + }, + { + "id" : "minecraft:arrow", + "damage" : 7 + }, + { + "id" : "minecraft:arrow", + "damage" : 8 + }, + { + "id" : "minecraft:arrow", + "damage" : 9 + }, + { + "id" : "minecraft:arrow", + "damage" : 10 + }, + { + "id" : "minecraft:arrow", + "damage" : 11 + }, + { + "id" : "minecraft:arrow", + "damage" : 12 + }, + { + "id" : "minecraft:arrow", + "damage" : 13 + }, + { + "id" : "minecraft:arrow", + "damage" : 14 + }, + { + "id" : "minecraft:arrow", + "damage" : 15 + }, + { + "id" : "minecraft:arrow", + "damage" : 16 + }, + { + "id" : "minecraft:arrow", + "damage" : 17 + }, + { + "id" : "minecraft:arrow", + "damage" : 18 + }, + { + "id" : "minecraft:arrow", + "damage" : 19 + }, + { + "id" : "minecraft:arrow", + "damage" : 20 + }, + { + "id" : "minecraft:arrow", + "damage" : 21 + }, + { + "id" : "minecraft:arrow", + "damage" : 22 + }, + { + "id" : "minecraft:arrow", + "damage" : 23 + }, + { + "id" : "minecraft:arrow", + "damage" : 24 + }, + { + "id" : "minecraft:arrow", + "damage" : 25 + }, + { + "id" : "minecraft:arrow", + "damage" : 26 + }, + { + "id" : "minecraft:arrow", + "damage" : 27 + }, + { + "id" : "minecraft:arrow", + "damage" : 28 + }, + { + "id" : "minecraft:arrow", + "damage" : 29 + }, + { + "id" : "minecraft:arrow", + "damage" : 30 + }, + { + "id" : "minecraft:arrow", + "damage" : 31 + }, + { + "id" : "minecraft:arrow", + "damage" : 32 + }, + { + "id" : "minecraft:arrow", + "damage" : 33 + }, + { + "id" : "minecraft:arrow", + "damage" : 34 + }, + { + "id" : "minecraft:arrow", + "damage" : 35 + }, + { + "id" : "minecraft:arrow", + "damage" : 36 + }, + { + "id" : "minecraft:arrow", + "damage" : 37 + }, + { + "id" : "minecraft:arrow", + "damage" : 38 + }, + { + "id" : "minecraft:arrow", + "damage" : 39 + }, + { + "id" : "minecraft:arrow", + "damage" : 40 + }, + { + "id" : "minecraft:arrow", + "damage" : 41 + }, + { + "id" : "minecraft:arrow", + "damage" : 42 + }, + { + "id" : "minecraft:arrow", + "damage" : 43 + }, + { + "id" : "minecraft:shield" + }, + { + "id" : "minecraft:cooked_chicken" + }, + { + "id" : "minecraft:cooked_porkchop" + }, + { + "id" : "minecraft:cooked_beef" + }, + { + "id" : "minecraft:cooked_mutton" + }, + { + "id" : "minecraft:cooked_rabbit" + }, + { + "id" : "minecraft:cooked_cod" + }, + { + "id" : "minecraft:cooked_salmon" + }, + { + "id" : "minecraft:bread" + }, + { + "id" : "minecraft:mushroom_stew" + }, + { + "id" : "minecraft:beetroot_soup" + }, + { + "id" : "minecraft:rabbit_stew" + }, + { + "id" : "minecraft:baked_potato" + }, + { + "id" : "minecraft:cookie" + }, + { + "id" : "minecraft:pumpkin_pie" + }, + { + "id" : "minecraft:cake" + }, + { + "id" : "minecraft:dried_kelp" + }, + { + "id" : "minecraft:fishing_rod" + }, + { + "id" : "minecraft:carrot_on_a_stick" + }, + { + "id" : "minecraft:warped_fungus_on_a_stick" + }, + { + "id" : "minecraft:snowball" + }, + { + "id" : "minecraft:shears" + }, + { + "id" : "minecraft:flint_and_steel" + }, + { + "id" : "minecraft:lead" + }, + { + "id" : "minecraft:clock" + }, + { + "id" : "minecraft:compass" + }, + { + "id" : "minecraft:recovery_compass" + }, + { + "id" : "minecraft:goat_horn" + }, + { + "id" : "minecraft:goat_horn", + "damage" : 1 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 2 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 3 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 4 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 5 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 6 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 7 + }, + { + "id" : "minecraft:empty_map" + }, + { + "id" : "minecraft:empty_map", + "damage" : 2 + }, + { + "id" : "minecraft:saddle" + }, + { + "id" : "minecraft:leather_horse_armor" + }, + { + "id" : "minecraft:iron_horse_armor" + }, + { + "id" : "minecraft:golden_horse_armor" + }, + { + "id" : "minecraft:diamond_horse_armor" + }, + { + "id" : "minecraft:trident" + }, + { + "id" : "minecraft:turtle_helmet" + }, + { + "id" : "minecraft:elytra" + }, + { + "id" : "minecraft:totem_of_undying" + }, + { + "id" : "minecraft:glass_bottle" + }, + { + "id" : "minecraft:experience_bottle" + }, + { + "id" : "minecraft:potion" + }, + { + "id" : "minecraft:potion", + "damage" : 1 + }, + { + "id" : "minecraft:potion", + "damage" : 2 + }, + { + "id" : "minecraft:potion", + "damage" : 3 + }, + { + "id" : "minecraft:potion", + "damage" : 4 + }, + { + "id" : "minecraft:potion", + "damage" : 5 + }, + { + "id" : "minecraft:potion", + "damage" : 6 + }, + { + "id" : "minecraft:potion", + "damage" : 7 + }, + { + "id" : "minecraft:potion", + "damage" : 8 + }, + { + "id" : "minecraft:potion", + "damage" : 9 + }, + { + "id" : "minecraft:potion", + "damage" : 10 + }, + { + "id" : "minecraft:potion", + "damage" : 11 + }, + { + "id" : "minecraft:potion", + "damage" : 12 + }, + { + "id" : "minecraft:potion", + "damage" : 13 + }, + { + "id" : "minecraft:potion", + "damage" : 14 + }, + { + "id" : "minecraft:potion", + "damage" : 15 + }, + { + "id" : "minecraft:potion", + "damage" : 16 + }, + { + "id" : "minecraft:potion", + "damage" : 17 + }, + { + "id" : "minecraft:potion", + "damage" : 18 + }, + { + "id" : "minecraft:potion", + "damage" : 19 + }, + { + "id" : "minecraft:potion", + "damage" : 20 + }, + { + "id" : "minecraft:potion", + "damage" : 21 + }, + { + "id" : "minecraft:potion", + "damage" : 22 + }, + { + "id" : "minecraft:potion", + "damage" : 23 + }, + { + "id" : "minecraft:potion", + "damage" : 24 + }, + { + "id" : "minecraft:potion", + "damage" : 25 + }, + { + "id" : "minecraft:potion", + "damage" : 26 + }, + { + "id" : "minecraft:potion", + "damage" : 27 + }, + { + "id" : "minecraft:potion", + "damage" : 28 + }, + { + "id" : "minecraft:potion", + "damage" : 29 + }, + { + "id" : "minecraft:potion", + "damage" : 30 + }, + { + "id" : "minecraft:potion", + "damage" : 31 + }, + { + "id" : "minecraft:potion", + "damage" : 32 + }, + { + "id" : "minecraft:potion", + "damage" : 33 + }, + { + "id" : "minecraft:potion", + "damage" : 34 + }, + { + "id" : "minecraft:potion", + "damage" : 35 + }, + { + "id" : "minecraft:potion", + "damage" : 36 + }, + { + "id" : "minecraft:potion", + "damage" : 37 + }, + { + "id" : "minecraft:potion", + "damage" : 38 + }, + { + "id" : "minecraft:potion", + "damage" : 39 + }, + { + "id" : "minecraft:potion", + "damage" : 40 + }, + { + "id" : "minecraft:potion", + "damage" : 41 + }, + { + "id" : "minecraft:potion", + "damage" : 42 + }, + { + "id" : "minecraft:splash_potion" + }, + { + "id" : "minecraft:splash_potion", + "damage" : 1 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 2 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 3 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 4 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 5 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 6 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 7 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 8 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 9 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 10 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 11 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 12 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 13 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 14 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 15 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 16 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 17 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 18 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 19 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 20 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 21 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 22 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 23 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 24 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 25 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 26 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 27 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 28 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 29 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 30 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 31 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 32 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 33 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 34 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 35 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 36 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 37 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 38 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 39 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 40 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 41 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 42 + }, + { + "id" : "minecraft:lingering_potion" + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 1 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 2 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 3 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 4 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 5 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 6 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 7 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 8 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 9 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 10 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 11 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 12 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 13 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 14 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 15 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 16 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 17 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 18 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 19 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 20 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 21 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 22 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 23 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 24 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 25 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 26 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 27 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 28 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 29 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 30 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 31 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 32 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 33 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 34 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 35 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 36 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 37 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 38 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 39 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 40 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 41 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 42 + }, + { + "id" : "minecraft:spyglass" + }, + { + "id" : "minecraft:stick" + }, + { + "id" : "minecraft:bed" + }, + { + "id" : "minecraft:bed", + "damage" : 8 + }, + { + "id" : "minecraft:bed", + "damage" : 7 + }, + { + "id" : "minecraft:bed", + "damage" : 15 + }, + { + "id" : "minecraft:bed", + "damage" : 12 + }, + { + "id" : "minecraft:bed", + "damage" : 14 + }, + { + "id" : "minecraft:bed", + "damage" : 1 + }, + { + "id" : "minecraft:bed", + "damage" : 4 + }, + { + "id" : "minecraft:bed", + "damage" : 5 + }, + { + "id" : "minecraft:bed", + "damage" : 13 + }, + { + "id" : "minecraft:bed", + "damage" : 9 + }, + { + "id" : "minecraft:bed", + "damage" : 3 + }, + { + "id" : "minecraft:bed", + "damage" : 11 + }, + { + "id" : "minecraft:bed", + "damage" : 10 + }, + { + "id" : "minecraft:bed", + "damage" : 2 + }, + { + "id" : "minecraft:bed", + "damage" : 6 + }, + { + "id" : "minecraft:torch", + "blockRuntimeId" : 726 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 4646 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 5857 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 7076 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 5751 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 7405 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 5302 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 364 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 420 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 4571 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 6194 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 6370 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 7372 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 941 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 6226 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 7728 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 7040 + }, + { + "id" : "minecraft:blue_candle" + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 5877 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 688 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 4683 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 171 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 5856 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 8290 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 5835 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 3728 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 6110 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 7804 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 7569 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 649 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 683 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6636 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6640 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6644 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 8041 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 6725 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 6673 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 6942 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 5417 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 7117 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 5585 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 4371 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 4520 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5318 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5326 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5325 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5333 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5330 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5332 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5319 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5322 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5323 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5331 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5327 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5321 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5329 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5328 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5320 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5324 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 348 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 4876 + }, + { + "id" : "minecraft:music_disc_13" + }, + { + "id" : "minecraft:music_disc_cat" + }, + { + "id" : "minecraft:music_disc_blocks" + }, + { + "id" : "minecraft:music_disc_chirp" + }, + { + "id" : "minecraft:music_disc_far" + }, + { + "id" : "minecraft:music_disc_mall" + }, + { + "id" : "minecraft:music_disc_mellohi" + }, + { + "id" : "minecraft:music_disc_stal" + }, + { + "id" : "minecraft:music_disc_strad" + }, + { + "id" : "minecraft:music_disc_ward" + }, + { + "id" : "minecraft:music_disc_11" + }, + { + "id" : "minecraft:music_disc_wait" + }, + { + "id" : "minecraft:music_disc_otherside" + }, + { + "id" : "minecraft:music_disc_5" + }, + { + "id" : "minecraft:music_disc_pigstep" + }, + { + "id" : "minecraft:disc_fragment_5" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 3887 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 251 + }, + { + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 7548 + }, + { + "id" : "minecraft:oak_sign" + }, + { + "id" : "minecraft:spruce_sign" + }, + { + "id" : "minecraft:birch_sign" + }, + { + "id" : "minecraft:jungle_sign" + }, + { + "id" : "minecraft:acacia_sign" + }, + { + "id" : "minecraft:dark_oak_sign" + }, + { + "id" : "minecraft:mangrove_sign" + }, + { + "id" : "minecraft:crimson_sign" + }, + { + "id" : "minecraft:warped_sign" + }, + { + "id" : "minecraft:painting" + }, + { + "id" : "minecraft:frame" + }, + { + "id" : "minecraft:glow_frame" + }, + { + "id" : "minecraft:honey_bottle" + }, + { + "id" : "minecraft:flower_pot" + }, + { + "id" : "minecraft:bowl" + }, + { + "id" : "minecraft:bucket" + }, + { + "id" : "minecraft:milk_bucket" + }, + { + "id" : "minecraft:water_bucket" + }, + { + "id" : "minecraft:lava_bucket" + }, + { + "id" : "minecraft:cod_bucket" + }, + { + "id" : "minecraft:salmon_bucket" + }, + { + "id" : "minecraft:tropical_fish_bucket" + }, + { + "id" : "minecraft:pufferfish_bucket" + }, + { + "id" : "minecraft:powder_snow_bucket" + }, + { + "id" : "minecraft:axolotl_bucket" + }, + { + "id" : "minecraft:tadpole_bucket" + }, + { + "id" : "minecraft:skull", + "damage" : 3 + }, + { + "id" : "minecraft:skull", + "damage" : 2 + }, + { + "id" : "minecraft:skull", + "damage" : 4 + }, + { + "id" : "minecraft:skull", + "damage" : 5 + }, + { + "id" : "minecraft:skull" + }, + { + "id" : "minecraft:skull", + "damage" : 1 + }, + { + "id" : "minecraft:beacon", + "blockRuntimeId" : 145 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 6910 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 4234 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 7576 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 6079 + }, + { + "id" : "minecraft:coal" + }, + { + "id" : "minecraft:charcoal" + }, + { + "id" : "minecraft:diamond" + }, + { + "id" : "minecraft:iron_nugget" + }, + { + "id" : "minecraft:raw_iron" + }, + { + "id" : "minecraft:raw_gold" + }, + { + "id" : "minecraft:raw_copper" + }, + { + "id" : "minecraft:copper_ingot" + }, + { + "id" : "minecraft:iron_ingot" + }, + { + "id" : "minecraft:netherite_scrap" + }, + { + "id" : "minecraft:netherite_ingot" + }, + { + "id" : "minecraft:gold_nugget" + }, + { + "id" : "minecraft:gold_ingot" + }, + { + "id" : "minecraft:emerald" + }, + { + "id" : "minecraft:quartz" + }, + { + "id" : "minecraft:clay_ball" + }, + { + "id" : "minecraft:brick" + }, + { + "id" : "minecraft:netherbrick" + }, + { + "id" : "minecraft:prismarine_shard" + }, + { + "id" : "minecraft:amethyst_shard" + }, + { + "id" : "minecraft:prismarine_crystals" + }, + { + "id" : "minecraft:nautilus_shell" + }, + { + "id" : "minecraft:heart_of_the_sea" + }, + { + "id" : "minecraft:scute" + }, + { + "id" : "minecraft:phantom_membrane" + }, + { + "id" : "minecraft:string" + }, + { + "id" : "minecraft:feather" + }, + { + "id" : "minecraft:flint" + }, + { + "id" : "minecraft:gunpowder" + }, + { + "id" : "minecraft:leather" + }, + { + "id" : "minecraft:rabbit_hide" + }, + { + "id" : "minecraft:rabbit_foot" + }, + { + "id" : "minecraft:fire_charge" + }, + { + "id" : "minecraft:blaze_rod" + }, + { + "id" : "minecraft:blaze_powder" + }, + { + "id" : "minecraft:magma_cream" + }, + { + "id" : "minecraft:fermented_spider_eye" + }, + { + "id" : "minecraft:echo_shard" + }, + { + "id" : "minecraft:dragon_breath" + }, + { + "id" : "minecraft:shulker_shell" + }, + { + "id" : "minecraft:ghast_tear" + }, + { + "id" : "minecraft:slime_ball" + }, + { + "id" : "minecraft:ender_pearl" + }, + { + "id" : "minecraft:ender_eye" + }, + { + "id" : "minecraft:nether_star" + }, + { + "id" : "minecraft:end_rod", + "blockRuntimeId" : 5893 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 1178 + }, + { + "id" : "minecraft:end_crystal" + }, + { + "id" : "minecraft:paper" + }, + { + "id" : "minecraft:book" + }, + { + "id" : "minecraft:writable_book" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:oak_boat" + }, + { + "id" : "minecraft:spruce_boat" + }, + { + "id" : "minecraft:birch_boat" + }, + { + "id" : "minecraft:jungle_boat" + }, + { + "id" : "minecraft:acacia_boat" + }, + { + "id" : "minecraft:dark_oak_boat" + }, + { + "id" : "minecraft:mangrove_boat" + }, + { + "id" : "minecraft:oak_chest_boat" + }, + { + "id" : "minecraft:spruce_chest_boat" + }, + { + "id" : "minecraft:birch_chest_boat" + }, + { + "id" : "minecraft:jungle_chest_boat" + }, + { + "id" : "minecraft:acacia_chest_boat" + }, + { + "id" : "minecraft:dark_oak_chest_boat" + }, + { + "id" : "minecraft:mangrove_chest_boat" + }, + { + "id" : "minecraft:rail", + "blockRuntimeId" : 3922 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 5334 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 4134 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 309 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 3778 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 3527 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 6516 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 6393 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 4323 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 7768 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 116 + }, + { + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 7233 + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 93 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 7064 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 598 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 4434 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 7252 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 7792 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 5916 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 8065 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 3761 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 3557 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 3637 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 5249 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 5958 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 3871 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 8270 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 256 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 3888 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 3667 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 1162 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 6234 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 3515 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 4199 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 7387 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 8015 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 924 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 4366 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 6709 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 3828 + }, + { + "id" : "minecraft:banner" + }, + { + "id" : "minecraft:banner", + "damage" : 8 + }, + { + "id" : "minecraft:banner", + "damage" : 7 + }, + { + "id" : "minecraft:banner", + "damage" : 15 + }, + { + "id" : "minecraft:banner", + "damage" : 12 + }, + { + "id" : "minecraft:banner", + "damage" : 14 + }, + { + "id" : "minecraft:banner", + "damage" : 1 + }, + { + "id" : "minecraft:banner", + "damage" : 4 + }, + { + "id" : "minecraft:banner", + "damage" : 5 + }, + { + "id" : "minecraft:banner", + "damage" : 13 + }, + { + "id" : "minecraft:banner", + "damage" : 9 + }, + { + "id" : "minecraft:banner", + "damage" : 3 + }, + { + "id" : "minecraft:banner", + "damage" : 11 + }, + { + "id" : "minecraft:banner", + "damage" : 10 + }, + { + "id" : "minecraft:banner", + "damage" : 2 + }, + { + "id" : "minecraft:banner", + "damage" : 6 + }, + { + "id" : "minecraft:banner", + "damage" : 15, + "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id" : "minecraft:creeper_banner_pattern" + }, + { + "id" : "minecraft:skull_banner_pattern" + }, + { + "id" : "minecraft:flower_banner_pattern" + }, + { + "id" : "minecraft:mojang_banner_pattern" + }, + { + "id" : "minecraft:field_masoned_banner_pattern" + }, + { + "id" : "minecraft:bordure_indented_banner_pattern" + }, + { + "id" : "minecraft:piglin_banner_pattern" + }, + { + "id" : "minecraft:globe_banner_pattern" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_star", + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 8, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 7, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 15, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 12, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 14, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 1, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 4, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 5, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 13, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 9, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 3, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 11, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 10, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 2, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 6, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id" : "minecraft:chain" + }, + { + "id" : "minecraft:target", + "blockRuntimeId" : 6392 + }, + { + "id" : "minecraft:lodestone_compass" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index b3e6fdb77103286cf60af2a14913f213fc1afd69..297d30537148f5cb80ecd63810b352f3e4c7ab03 100644 GIT binary patch delta 776 zcmX|9OK4M35H-K%b6@gazD-TiJPCr5Ce6P!Kbt14TBYj3h0rQRRD@Dd6t{}|ko2JV zfoxo8MFd^BQc4#tZLNFe$4L`m5OGtv*@Bi`;MHIaH-njFzra0j z8cvTBv%WEzo~85?4e9v{_+SxuqU9v~*^}W}sxN~wN?!kEeJ(wGDt=9G@_{r ztb|lt4~;O zIHTs;x`v;@Btu1;fT|Xx0I4=Hw8-!-!K<#SggZm;SVzlOpzZxe$0#sIzv+Z#cx&5X z`k;bq^r0rrP6hMKun;-HZNEYVE_)N{GfNE*+~b5*X~_q0-WkLV*CcM!#JVdDT?p7* zDXdW4nzM*o&Ki$wIJ5Yn94CAVQuLBiLR4w+y1t4s9*YXQbV=liV;bKbc|3BQ#zl&f zOLr8}wb#kLN$L}@+Z9}}C$MXqrP*cToMzshwL~=v-dYQ|Vm*eBWXp)PLh&fScLsP_ zGXssjX(ig*1iR3&^qrrxkkxWNSy;^6z>;Z{jY=A_ z(!lo1LwpY33@L<6_5W<=j4_-t4I^fZOBQ*%PkMMD)^res?`iEU#}>S^z!<>K2{ P`Tm}nqPSzM8}|GGV~6qnRs@$0l0jF|+1f=HA^Lr9(c$>+d*6GW_j#Y^#?IL3&!8(a{K_^k zG-q*`ZsVT8aN8_mm|o-$!=3CRoUDy07ehT`(do+OG0fOdb1hs;8^lrO_?wy5;G{&K z^wOvC*2D0_oEr3Vc%3caqAp=u=PZ1RhqrfARjPgD%nwp!)KhZ;eb>wI-YB8(((uqI zqHZh^qheUtO}6nx*U(K?2%1l>BA;Y9Ow{o#v4&ABgzJe4cA^YsqDJTEcn$ry!+Q+A z)Ev4&hV^(0lUSSAma!FUk*r3n3L)iBw9Ijru*FY1x`IhWNDJXzq=?PP8IEJ9L>7qq zNUw2h2bcA8$mbZQbsL|wChZH#=&*z-0hoQXgG-!{c#{WE;UXOXn&@I2+V?=KO}NIIq#^2VVO z3V{v<G25ya=1F G6Mq3QY4m~s diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json new file mode 100644 index 000000000..00be1af06 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json @@ -0,0 +1,4530 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 379 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 642 + }, + { + "name" : "minecraft:acacia_door", + "id" : 556 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 579 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:acacia_wall_sign", + "id" : -191 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:agent_spawn_egg", + "id" : 487 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 631 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 624 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:armor_stand", + "id" : 552 + }, + { + "name" : "minecraft:arrow", + "id" : 301 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 369 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 500 + }, + { + "name" : "minecraft:azalea", + "id" : -337 + }, + { + "name" : "minecraft:azalea_leaves", + "id" : -324 + }, + { + "name" : "minecraft:azalea_leaves_flowered", + "id" : -325 + }, + { + "name" : "minecraft:baked_potato", + "id" : 281 + }, + { + "name" : "minecraft:balloon", + "id" : 598 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:banner", + "id" : 567 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 651 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 418 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 494 + }, + { + "name" : "minecraft:beef", + "id" : 273 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:beetroot", + "id" : 285 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 295 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 286 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:big_dripleaf", + "id" : -323 + }, + { + "name" : "minecraft:birch_boat", + "id" : 376 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 639 + }, + { + "name" : "minecraft:birch_door", + "id" : 554 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 577 + }, + { + "name" : "minecraft:birch_stairs", + "id" : 135 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:black_candle", + "id" : -428 + }, + { + "name" : "minecraft:black_candle_cake", + "id" : -445 + }, + { + "name" : "minecraft:black_dye", + "id" : 395 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:blackstone", + "id" : -273 + }, + { + "name" : "minecraft:blackstone_double_slab", + "id" : -283 + }, + { + "name" : "minecraft:blackstone_slab", + "id" : -282 + }, + { + "name" : "minecraft:blackstone_stairs", + "id" : -276 + }, + { + "name" : "minecraft:blackstone_wall", + "id" : -277 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 429 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 423 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:bleach", + "id" : 596 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 399 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:boat", + "id" : 649 + }, + { + "name" : "minecraft:bone", + "id" : 415 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 411 + }, + { + "name" : "minecraft:book", + "id" : 387 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 586 + }, + { + "name" : "minecraft:bow", + "id" : 300 + }, + { + "name" : "minecraft:bowl", + "id" : 321 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 431 + }, + { + "name" : "minecraft:brick", + "id" : 383 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:brown_candle", + "id" : -425 + }, + { + "name" : "minecraft:brown_candle_cake", + "id" : -442 + }, + { + "name" : "minecraft:brown_dye", + "id" : 398 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 360 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 417 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camera", + "id" : 593 + }, + { + "name" : "minecraft:campfire", + "id" : 589 + }, + { + "name" : "minecraft:candle", + "id" : -412 + }, + { + "name" : "minecraft:candle_cake", + "id" : -429 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:carrot", + "id" : 279 + }, + { + "name" : "minecraft:carrot_on_a_stick", + "id" : 517 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:cauldron", + "id" : 432 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 457 + }, + { + "name" : "minecraft:cave_vines", + "id" : -322 + }, + { + "name" : "minecraft:cave_vines_body_with_berries", + "id" : -375 + }, + { + "name" : "minecraft:cave_vines_head_with_berries", + "id" : -376 + }, + { + "name" : "minecraft:chain", + "id" : 619 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 342 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 339 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 341 + }, + { + "name" : "minecraft:charcoal", + "id" : 303 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 389 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 435 + }, + { + "name" : "minecraft:chiseled_deepslate", + "id" : -395 + }, + { + "name" : "minecraft:chiseled_nether_bricks", + "id" : -302 + }, + { + "name" : "minecraft:chiseled_polished_blackstone", + "id" : -279 + }, + { + "name" : "minecraft:chorus_flower", + "id" : 200 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 558 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 384 + }, + { + "name" : "minecraft:client_request_placeholder_block", + "id" : -465 + }, + { + "name" : "minecraft:clock", + "id" : 393 + }, + { + "name" : "minecraft:coal", + "id" : 302 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:cobbled_deepslate", + "id" : -379 + }, + { + "name" : "minecraft:cobbled_deepslate_double_slab", + "id" : -396 + }, + { + "name" : "minecraft:cobbled_deepslate_slab", + "id" : -380 + }, + { + "name" : "minecraft:cobbled_deepslate_stairs", + "id" : -381 + }, + { + "name" : "minecraft:cobbled_deepslate_wall", + "id" : -382 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:cocoa_beans", + "id" : 412 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 364 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 480 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 563 + }, + { + "name" : "minecraft:comparator", + "id" : 522 + }, + { + "name" : "minecraft:compass", + "id" : 391 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 594 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:cooked_beef", + "id" : 274 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 276 + }, + { + "name" : "minecraft:cooked_cod", + "id" : 268 + }, + { + "name" : "minecraft:cooked_mutton", + "id" : 551 + }, + { + "name" : "minecraft:cooked_porkchop", + "id" : 263 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 289 + }, + { + "name" : "minecraft:cooked_salmon", + "id" : 269 + }, + { + "name" : "minecraft:cookie", + "id" : 271 + }, + { + "name" : "minecraft:copper_block", + "id" : -340 + }, + { + "name" : "minecraft:copper_ingot", + "id" : 504 + }, + { + "name" : "minecraft:copper_ore", + "id" : -311 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:cow_spawn_egg", + "id" : 436 + }, + { + "name" : "minecraft:cracked_deepslate_bricks", + "id" : -410 + }, + { + "name" : "minecraft:cracked_deepslate_tiles", + "id" : -409 + }, + { + "name" : "minecraft:cracked_nether_bricks", + "id" : -303 + }, + { + "name" : "minecraft:cracked_polished_blackstone_bricks", + "id" : -280 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, + { + "name" : "minecraft:creeper_banner_pattern", + "id" : 582 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 616 + }, + { + "name" : "minecraft:crimson_double_slab", + "id" : -266 + }, + { + "name" : "minecraft:crimson_fence", + "id" : -256 + }, + { + "name" : "minecraft:crimson_fence_gate", + "id" : -258 + }, + { + "name" : "minecraft:crimson_fungus", + "id" : -228 + }, + { + "name" : "minecraft:crimson_hyphae", + "id" : -299 + }, + { + "name" : "minecraft:crimson_nylium", + "id" : -232 + }, + { + "name" : "minecraft:crimson_planks", + "id" : -242 + }, + { + "name" : "minecraft:crimson_pressure_plate", + "id" : -262 + }, + { + "name" : "minecraft:crimson_roots", + "id" : -223 + }, + { + "name" : "minecraft:crimson_sign", + "id" : 614 + }, + { + "name" : "minecraft:crimson_slab", + "id" : -264 + }, + { + "name" : "minecraft:crimson_stairs", + "id" : -254 + }, + { + "name" : "minecraft:crimson_standing_sign", + "id" : -250 + }, + { + "name" : "minecraft:crimson_stem", + "id" : -225 + }, + { + "name" : "minecraft:crimson_trapdoor", + "id" : -246 + }, + { + "name" : "minecraft:crimson_wall_sign", + "id" : -252 + }, + { + "name" : "minecraft:crossbow", + "id" : 575 + }, + { + "name" : "minecraft:crying_obsidian", + "id" : -289 + }, + { + "name" : "minecraft:cut_copper", + "id" : -347 + }, + { + "name" : "minecraft:cut_copper_slab", + "id" : -361 + }, + { + "name" : "minecraft:cut_copper_stairs", + "id" : -354 + }, + { + "name" : "minecraft:cyan_candle", + "id" : -422 + }, + { + "name" : "minecraft:cyan_candle_cake", + "id" : -439 + }, + { + "name" : "minecraft:cyan_dye", + "id" : 401 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 380 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 643 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 557 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 580 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:daylight_detector_inverted", + "id" : 178 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:deepslate", + "id" : -378 + }, + { + "name" : "minecraft:deepslate_brick_double_slab", + "id" : -399 + }, + { + "name" : "minecraft:deepslate_brick_slab", + "id" : -392 + }, + { + "name" : "minecraft:deepslate_brick_stairs", + "id" : -393 + }, + { + "name" : "minecraft:deepslate_brick_wall", + "id" : -394 + }, + { + "name" : "minecraft:deepslate_bricks", + "id" : -391 + }, + { + "name" : "minecraft:deepslate_coal_ore", + "id" : -406 + }, + { + "name" : "minecraft:deepslate_copper_ore", + "id" : -408 + }, + { + "name" : "minecraft:deepslate_diamond_ore", + "id" : -405 + }, + { + "name" : "minecraft:deepslate_emerald_ore", + "id" : -407 + }, + { + "name" : "minecraft:deepslate_gold_ore", + "id" : -402 + }, + { + "name" : "minecraft:deepslate_iron_ore", + "id" : -401 + }, + { + "name" : "minecraft:deepslate_lapis_ore", + "id" : -400 + }, + { + "name" : "minecraft:deepslate_redstone_ore", + "id" : -403 + }, + { + "name" : "minecraft:deepslate_tile_double_slab", + "id" : -398 + }, + { + "name" : "minecraft:deepslate_tile_slab", + "id" : -388 + }, + { + "name" : "minecraft:deepslate_tile_stairs", + "id" : -389 + }, + { + "name" : "minecraft:deepslate_tile_wall", + "id" : -390 + }, + { + "name" : "minecraft:deepslate_tiles", + "id" : -387 + }, + { + "name" : "minecraft:deny", + "id" : 211 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:diamond", + "id" : 304 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 350 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 348 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 347 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 332 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 533 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 349 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 318 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 317 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 316 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 637 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 465 + }, + { + "name" : "minecraft:double_cut_copper_slab", + "id" : -368 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:double_stone_block_slab", + "id" : 43 + }, + { + "name" : "minecraft:double_stone_block_slab2", + "id" : 181 + }, + { + "name" : "minecraft:double_stone_block_slab3", + "id" : -167 + }, + { + "name" : "minecraft:double_stone_block_slab4", + "id" : -168 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 560 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:dried_kelp", + "id" : 270 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:dripstone_block", + "id" : -317 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:drowned_spawn_egg", + "id" : 483 + }, + { + "name" : "minecraft:dye", + "id" : 650 + }, + { + "name" : "minecraft:echo_shard", + "id" : 647 + }, + { + "name" : "minecraft:egg", + "id" : 390 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 471 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_1", + "id" : -12 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:element_104", + "id" : -115 + }, + { + "name" : "minecraft:element_105", + "id" : -116 + }, + { + "name" : "minecraft:element_106", + "id" : -117 + }, + { + "name" : "minecraft:element_107", + "id" : -118 + }, + { + "name" : "minecraft:element_108", + "id" : -119 + }, + { + "name" : "minecraft:element_109", + "id" : -120 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:element_112", + "id" : -123 + }, + { + "name" : "minecraft:element_113", + "id" : -124 + }, + { + "name" : "minecraft:element_114", + "id" : -125 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:element_116", + "id" : -127 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:element_118", + "id" : -129 + }, + { + "name" : "minecraft:element_12", + "id" : -23 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:element_14", + "id" : -25 + }, + { + "name" : "minecraft:element_15", + "id" : -26 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:element_18", + "id" : -29 + }, + { + "name" : "minecraft:element_19", + "id" : -30 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:element_20", + "id" : -31 + }, + { + "name" : "minecraft:element_21", + "id" : -32 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:element_25", + "id" : -36 + }, + { + "name" : "minecraft:element_26", + "id" : -37 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:element_28", + "id" : -39 + }, + { + "name" : "minecraft:element_29", + "id" : -40 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:element_33", + "id" : -44 + }, + { + "name" : "minecraft:element_34", + "id" : -45 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:element_36", + "id" : -47 + }, + { + "name" : "minecraft:element_37", + "id" : -48 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:element_39", + "id" : -50 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:element_40", + "id" : -51 + }, + { + "name" : "minecraft:element_41", + "id" : -52 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:element_45", + "id" : -56 + }, + { + "name" : "minecraft:element_46", + "id" : -57 + }, + { + "name" : "minecraft:element_47", + "id" : -58 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:element_54", + "id" : -65 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:element_56", + "id" : -67 + }, + { + "name" : "minecraft:element_57", + "id" : -68 + }, + { + "name" : "minecraft:element_58", + "id" : -69 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_60", + "id" : -71 + }, + { + "name" : "minecraft:element_61", + "id" : -72 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:element_64", + "id" : -75 + }, + { + "name" : "minecraft:element_65", + "id" : -76 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:element_67", + "id" : -78 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, + { + "name" : "minecraft:element_70", + "id" : -81 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:element_72", + "id" : -83 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:element_76", + "id" : -87 + }, + { + "name" : "minecraft:element_77", + "id" : -88 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:element_79", + "id" : -90 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_80", + "id" : -91 + }, + { + "name" : "minecraft:element_81", + "id" : -92 + }, + { + "name" : "minecraft:element_82", + "id" : -93 + }, + { + "name" : "minecraft:element_83", + "id" : -94 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:element_89", + "id" : -100 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:element_91", + "id" : -102 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:element_94", + "id" : -105 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:element_96", + "id" : -107 + }, + { + "name" : "minecraft:element_97", + "id" : -108 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:element_99", + "id" : -110 + }, + { + "name" : "minecraft:elytra", + "id" : 564 + }, + { + "name" : "minecraft:emerald", + "id" : 512 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 515 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 521 + }, + { + "name" : "minecraft:enchanted_golden_apple", + "id" : 259 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:end_bricks", + "id" : 206 + }, + { + "name" : "minecraft:end_crystal", + "id" : 653 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:ender_eye", + "id" : 433 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 422 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 508 + }, + { + "name" : "minecraft:exposed_copper", + "id" : -341 + }, + { + "name" : "minecraft:exposed_cut_copper", + "id" : -348 + }, + { + "name" : "minecraft:exposed_cut_copper_slab", + "id" : -362 + }, + { + "name" : "minecraft:exposed_cut_copper_stairs", + "id" : -355 + }, + { + "name" : "minecraft:exposed_double_cut_copper_slab", + "id" : -369 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:feather", + "id" : 327 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 428 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 585 + }, + { + "name" : "minecraft:filled_map", + "id" : 420 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 509 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 519 + }, + { + "name" : "minecraft:firework_star", + "id" : 520 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 392 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 356 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 299 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 581 + }, + { + "name" : "minecraft:flower_pot", + "id" : 514 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:frame", + "id" : 513 + }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 628 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 424 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 427 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 434 + }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 588 + }, + { + "name" : "minecraft:glow_berries", + "id" : 654 + }, + { + "name" : "minecraft:glow_frame", + "id" : 623 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 503 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:glow_stick", + "id" : 601 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 394 + }, + { + "name" : "minecraft:goat_horn", + "id" : 627 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 306 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 425 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 325 + }, + { + "name" : "minecraft:golden_boots", + "id" : 354 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 352 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 351 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 333 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 532 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 353 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 324 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 323 + }, + { + "name" : "minecraft:golden_sword", + "id" : 322 + }, + { + "name" : "minecraft:granite_stairs", + "id" : -169 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:grass_path", + "id" : 198 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:gray_candle", + "id" : -420 + }, + { + "name" : "minecraft:gray_candle_cake", + "id" : -437 + }, + { + "name" : "minecraft:gray_dye", + "id" : 403 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 397 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:gunpowder", + "id" : 328 + }, + { + "name" : "minecraft:hanging_roots", + "id" : -319 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:hardened_clay", + "id" : 172 + }, + { + "name" : "minecraft:hay_block", + "id" : 170 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 571 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 592 + }, + { + "name" : "minecraft:honeycomb", + "id" : 591 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 527 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 526 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 595 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 413 + }, + { + "name" : "minecraft:invisible_bedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 298 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 346 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 344 + }, + { + "name" : "minecraft:iron_door", + "id" : 372 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 343 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 331 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 531 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 305 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 345 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 569 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 297 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 296 + }, + { + "name" : "minecraft:iron_sword", + "id" : 307 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:item.birch_door", + "id" : 194 + }, + { + "name" : "minecraft:item.brewing_stand", + "id" : 117 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:item.cauldron", + "id" : 118 + }, + { + "name" : "minecraft:item.chain", + "id" : -286 + }, + { + "name" : "minecraft:item.crimson_door", + "id" : -244 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:item.glow_frame", + "id" : -339 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:item.mangrove_door", + "id" : -493 + }, + { + "name" : "minecraft:item.nether_sprouts", + "id" : -238 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:item.skull", + "id" : 144 + }, + { + "name" : "minecraft:item.soul_campfire", + "id" : -290 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:item.warped_door", + "id" : -245 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:jungle_boat", + "id" : 377 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 640 + }, + { + "name" : "minecraft:jungle_door", + "id" : 555 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 578 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:kelp", + "id" : 382 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 414 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 363 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 547 + }, + { + "name" : "minecraft:leather", + "id" : 381 + }, + { + "name" : "minecraft:leather_boots", + "id" : 338 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 336 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 335 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 530 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 337 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:light_blue_candle", + "id" : -416 + }, + { + "name" : "minecraft:light_blue_candle_cake", + "id" : -433 + }, + { + "name" : "minecraft:light_blue_dye", + "id" : 407 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 402 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:lightning_rod", + "id" : -312 + }, + { + "name" : "minecraft:lime_candle", + "id" : -418 + }, + { + "name" : "minecraft:lime_candle_cake", + "id" : -435 + }, + { + "name" : "minecraft:lime_dye", + "id" : 405 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 562 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:lit_deepslate_redstone_ore", + "id" : -404 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:llama_spawn_egg", + "id" : 473 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 602 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:magenta_candle", + "id" : -415 + }, + { + "name" : "minecraft:magenta_candle_cake", + "id" : -432 + }, + { + "name" : "minecraft:magenta_dye", + "id" : 408 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 430 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:mangrove_boat", + "id" : 635 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 644 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 633 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "name" : "minecraft:mangrove_leaves", + "id" : -472 + }, + { + "name" : "minecraft:mangrove_log", + "id" : -484 + }, + { + "name" : "minecraft:mangrove_planks", + "id" : -486 + }, + { + "name" : "minecraft:mangrove_pressure_plate", + "id" : -490 + }, + { + "name" : "minecraft:mangrove_propagule", + "id" : -474 + }, + { + "name" : "minecraft:mangrove_roots", + "id" : -482 + }, + { + "name" : "minecraft:mangrove_sign", + "id" : 634 + }, + { + "name" : "minecraft:mangrove_slab", + "id" : -489 + }, + { + "name" : "minecraft:mangrove_stairs", + "id" : -488 + }, + { + "name" : "minecraft:mangrove_standing_sign", + "id" : -494 + }, + { + "name" : "minecraft:mangrove_trapdoor", + "id" : -496 + }, + { + "name" : "minecraft:mangrove_wall_sign", + "id" : -495 + }, + { + "name" : "minecraft:mangrove_wood", + "id" : -497 + }, + { + "name" : "minecraft:medicine", + "id" : 599 + }, + { + "name" : "minecraft:medium_amethyst_bud", + "id" : -331 + }, + { + "name" : "minecraft:melon_block", + "id" : 103 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 293 + }, + { + "name" : "minecraft:melon_slice", + "id" : 272 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:milk_bucket", + "id" : 361 + }, + { + "name" : "minecraft:minecart", + "id" : 370 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 584 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 440 + }, + { + "name" : "minecraft:moss_block", + "id" : -320 + }, + { + "name" : "minecraft:moss_carpet", + "id" : -335 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:moving_block", + "id" : 250 + }, + { + "name" : "minecraft:mud", + "id" : -473 + }, + { + "name" : "minecraft:mud_brick_double_slab", + "id" : -479 + }, + { + "name" : "minecraft:mud_brick_slab", + "id" : -478 + }, + { + "name" : "minecraft:mud_brick_stairs", + "id" : -480 + }, + { + "name" : "minecraft:mud_brick_wall", + "id" : -481 + }, + { + "name" : "minecraft:mud_bricks", + "id" : -475 + }, + { + "name" : "minecraft:muddy_mangrove_roots", + "id" : -483 + }, + { + "name" : "minecraft:mule_spawn_egg", + "id" : 466 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 534 + }, + { + "name" : "minecraft:music_disc_5", + "id" : 636 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 536 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 535 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 537 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 538 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 539 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_otherside", + "id" : 626 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 620 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 543 + }, + { + "name" : "minecraft:mutton", + "id" : 550 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 548 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 570 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:nether_gold_ore", + "id" : -288 + }, + { + "name" : "minecraft:nether_sprouts", + "id" : 621 + }, + { + "name" : "minecraft:nether_star", + "id" : 518 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 523 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 607 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 612 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 610 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 609 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 608 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 603 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 611 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 613 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 605 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 604 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:normal_stone_stairs", + "id" : -180 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:npc_spawn_egg", + "id" : 470 + }, + { + "name" : "minecraft:oak_boat", + "id" : 375 + }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 638 + }, + { + "name" : "minecraft:oak_sign", + "id" : 358 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 409 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:oxidized_copper", + "id" : -343 + }, + { + "name" : "minecraft:oxidized_cut_copper", + "id" : -350 + }, + { + "name" : "minecraft:oxidized_cut_copper_slab", + "id" : -364 + }, + { + "name" : "minecraft:oxidized_cut_copper_stairs", + "id" : -357 + }, + { + "name" : "minecraft:oxidized_double_cut_copper_slab", + "id" : -371 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:packed_mud", + "id" : -477 + }, + { + "name" : "minecraft:painting", + "id" : 357 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:paper", + "id" : 386 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 478 + }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 574 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 404 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:piston_arm_collision", + "id" : 34 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:pointed_dripstone", + "id" : -308 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 282 + }, + { + "name" : "minecraft:polar_bear_spawn_egg", + "id" : 472 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:polished_basalt", + "id" : -235 + }, + { + "name" : "minecraft:polished_blackstone", + "id" : -291 + }, + { + "name" : "minecraft:polished_blackstone_brick_double_slab", + "id" : -285 + }, + { + "name" : "minecraft:polished_blackstone_brick_slab", + "id" : -284 + }, + { + "name" : "minecraft:polished_blackstone_brick_stairs", + "id" : -275 + }, + { + "name" : "minecraft:polished_blackstone_brick_wall", + "id" : -278 + }, + { + "name" : "minecraft:polished_blackstone_bricks", + "id" : -274 + }, + { + "name" : "minecraft:polished_blackstone_button", + "id" : -296 + }, + { + "name" : "minecraft:polished_blackstone_double_slab", + "id" : -294 + }, + { + "name" : "minecraft:polished_blackstone_pressure_plate", + "id" : -295 + }, + { + "name" : "minecraft:polished_blackstone_slab", + "id" : -293 + }, + { + "name" : "minecraft:polished_blackstone_stairs", + "id" : -292 + }, + { + "name" : "minecraft:polished_blackstone_wall", + "id" : -297 + }, + { + "name" : "minecraft:polished_deepslate", + "id" : -383 + }, + { + "name" : "minecraft:polished_deepslate_double_slab", + "id" : -397 + }, + { + "name" : "minecraft:polished_deepslate_slab", + "id" : -384 + }, + { + "name" : "minecraft:polished_deepslate_stairs", + "id" : -385 + }, + { + "name" : "minecraft:polished_deepslate_wall", + "id" : -386 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:popped_chorus_fruit", + "id" : 559 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 426 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 368 + }, + { + "name" : "minecraft:powered_comparator", + "id" : 150 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 549 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 565 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 481 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 284 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 292 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:purple_candle", + "id" : -423 + }, + { + "name" : "minecraft:purple_candle_cake", + "id" : -440 + }, + { + "name" : "minecraft:purple_dye", + "id" : 400 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 524 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:quartz_bricks", + "id" : -304 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:rabbit", + "id" : 288 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 528 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 529 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 597 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:raw_copper", + "id" : 507 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 506 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 505 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:recovery_compass", + "id" : 646 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 396 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:redstone", + "id" : 373 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:reinforced_deepslate", + "id" : -466 + }, + { + "name" : "minecraft:repeater", + "id" : 419 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 277 + }, + { + "name" : "minecraft:saddle", + "id" : 371 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 365 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 482 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:sculk", + "id" : -458 + }, + { + "name" : "minecraft:sculk_catalyst", + "id" : -460 + }, + { + "name" : "minecraft:sculk_sensor", + "id" : -307 + }, + { + "name" : "minecraft:sculk_shrieker", + "id" : -461 + }, + { + "name" : "minecraft:sculk_vein", + "id" : -459 + }, + { + "name" : "minecraft:scute", + "id" : 572 + }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:shears", + "id" : 421 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:shield", + "id" : 355 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 566 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skull", + "id" : 516 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 583 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 388 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 445 + }, + { + "name" : "minecraft:small_amethyst_bud", + "id" : -332 + }, + { + "name" : "minecraft:small_dripleaf_block", + "id" : -336 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:smooth_basalt", + "id" : -377 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 374 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 622 + }, + { + "name" : "minecraft:soul_fire", + "id" : -237 + }, + { + "name" : "minecraft:soul_lantern", + "id" : -269 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:soul_soil", + "id" : -236 + }, + { + "name" : "minecraft:soul_torch", + "id" : -268 + }, + { + "name" : "minecraft:sparkler", + "id" : 600 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 652 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:splash_potion", + "id" : 561 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 378 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 641 + }, + { + "name" : "minecraft:spruce_door", + "id" : 553 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 576 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:spruce_trapdoor", + "id" : -149 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:spyglass", + "id" : 625 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 450 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:stick", + "id" : 320 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:sticky_piston_arm_collision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 315 + }, + { + "name" : "minecraft:stone_block_slab", + "id" : 44 + }, + { + "name" : "minecraft:stone_block_slab2", + "id" : 182 + }, + { + "name" : "minecraft:stone_block_slab3", + "id" : -162 + }, + { + "name" : "minecraft:stone_block_slab4", + "id" : -166 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 330 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 314 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 313 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 312 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:string", + "id" : 326 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:stripped_crimson_hyphae", + "id" : -300 + }, + { + "name" : "minecraft:stripped_crimson_stem", + "id" : -240 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:stripped_jungle_log", + "id" : -7 + }, + { + "name" : "minecraft:stripped_mangrove_log", + "id" : -485 + }, + { + "name" : "minecraft:stripped_mangrove_wood", + "id" : -498 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_warped_hyphae", + "id" : -301 + }, + { + "name" : "minecraft:stripped_warped_stem", + "id" : -241 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:sugar", + "id" : 416 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 385 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 590 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 630 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 629 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:tinted_glass", + "id" : -334 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 525 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 568 + }, + { + "name" : "minecraft:trader_llama_spawn_egg", + "id" : 648 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 546 + }, + { + "name" : "minecraft:trip_wire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 366 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 573 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 485 + }, + { + "name" : "minecraft:twisting_vines", + "id" : -287 + }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:unknown", + "id" : -305 + }, + { + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:verdant_froglight", + "id" : -470 + }, + { + "name" : "minecraft:vex_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 632 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 617 + }, + { + "name" : "minecraft:warped_double_slab", + "id" : -267 + }, + { + "name" : "minecraft:warped_fence", + "id" : -257 + }, + { + "name" : "minecraft:warped_fence_gate", + "id" : -259 + }, + { + "name" : "minecraft:warped_fungus", + "id" : -229 + }, + { + "name" : "minecraft:warped_fungus_on_a_stick", + "id" : 618 + }, + { + "name" : "minecraft:warped_hyphae", + "id" : -298 + }, + { + "name" : "minecraft:warped_nylium", + "id" : -233 + }, + { + "name" : "minecraft:warped_planks", + "id" : -243 + }, + { + "name" : "minecraft:warped_pressure_plate", + "id" : -263 + }, + { + "name" : "minecraft:warped_roots", + "id" : -224 + }, + { + "name" : "minecraft:warped_sign", + "id" : 615 + }, + { + "name" : "minecraft:warped_slab", + "id" : -265 + }, + { + "name" : "minecraft:warped_stairs", + "id" : -255 + }, + { + "name" : "minecraft:warped_standing_sign", + "id" : -251 + }, + { + "name" : "minecraft:warped_stem", + "id" : -226 + }, + { + "name" : "minecraft:warped_trapdoor", + "id" : -247 + }, + { + "name" : "minecraft:warped_wall_sign", + "id" : -253 + }, + { + "name" : "minecraft:warped_wart_block", + "id" : -227 + }, + { + "name" : "minecraft:water", + "id" : 9 + }, + { + "name" : "minecraft:water_bucket", + "id" : 362 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:waxed_copper", + "id" : -344 + }, + { + "name" : "minecraft:waxed_cut_copper", + "id" : -351 + }, + { + "name" : "minecraft:waxed_cut_copper_slab", + "id" : -365 + }, + { + "name" : "minecraft:waxed_cut_copper_stairs", + "id" : -358 + }, + { + "name" : "minecraft:waxed_double_cut_copper_slab", + "id" : -372 + }, + { + "name" : "minecraft:waxed_exposed_copper", + "id" : -345 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper", + "id" : -352 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_slab", + "id" : -366 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_stairs", + "id" : -359 + }, + { + "name" : "minecraft:waxed_exposed_double_cut_copper_slab", + "id" : -373 + }, + { + "name" : "minecraft:waxed_oxidized_copper", + "id" : -446 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper", + "id" : -447 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_slab", + "id" : -449 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_stairs", + "id" : -448 + }, + { + "name" : "minecraft:waxed_oxidized_double_cut_copper_slab", + "id" : -450 + }, + { + "name" : "minecraft:waxed_weathered_copper", + "id" : -346 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper", + "id" : -353 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_slab", + "id" : -367 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_stairs", + "id" : -360 + }, + { + "name" : "minecraft:waxed_weathered_double_cut_copper_slab", + "id" : -374 + }, + { + "name" : "minecraft:weathered_copper", + "id" : -342 + }, + { + "name" : "minecraft:weathered_cut_copper", + "id" : -349 + }, + { + "name" : "minecraft:weathered_cut_copper_slab", + "id" : -363 + }, + { + "name" : "minecraft:weathered_cut_copper_stairs", + "id" : -356 + }, + { + "name" : "minecraft:weathered_double_cut_copper_slab", + "id" : -370 + }, + { + "name" : "minecraft:web", + "id" : 30 + }, + { + "name" : "minecraft:weeping_vines", + "id" : -231 + }, + { + "name" : "minecraft:wheat", + "id" : 334 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 410 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 359 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 329 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 310 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 309 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 308 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:writable_book", + "id" : 510 + }, + { + "name" : "minecraft:written_book", + "id" : 511 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 406 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 477 + } +] \ No newline at end of file From eab92da98884308b6e4b4a5deb1de97b2fbd3c6e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Aug 2022 19:07:11 -0400 Subject: [PATCH 122/290] Fix form responses on 1.19.20 --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 88bde3360..372b5769a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -129,7 +129,7 @@ com.github.CloudburstMC.Protocol bedrock-v544 - 92d9854 + 0bd459f compile From 88727fb473fff1f1040c34ac64c52a2d4153880c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Aug 2022 20:30:49 -0400 Subject: [PATCH 123/290] Bump Geyser to version 2.0.7-SNAPSHOT and default Bedrock to 1.19.20 --- ap/pom.xml | 4 ++-- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 ++-- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 4 ++-- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 2 +- core/pom.xml | 8 ++++---- .../org/geysermc/geyser/network/MinecraftProtocol.java | 6 +++--- pom.xml | 2 +- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ap/pom.xml b/ap/pom.xml index 90bb1dc73..feb77e922 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT ap - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index 0eeb536ea..4e172650e 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 0071668bf..9aa8560d1 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index 9b4816954..79e999c16 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 4ec01539f..5a1e8e262 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 0da863811..371ed9bca 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 25bcb23f9..5142d2bc3 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-spigot @@ -30,7 +30,7 @@ org.geysermc core - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 25f709ec4..fc7bbc624 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 5d27c8a2a..5577f9206 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 0c530b21e..35e6df15b 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index 5326ca014..0b1153230 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT common diff --git a/core/pom.xml b/core/pom.xml index 372b5769a..489f99cb3 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT core @@ -29,19 +29,19 @@ org.geysermc ap - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT provided org.geysermc geyser-api - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile org.geysermc common - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT compile diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index e0a06b5e3..3452ec7d5 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -45,7 +45,7 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v534.V534_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v544.V544_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -61,10 +61,10 @@ public final class MinecraftProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v527.V527_CODEC.toBuilder() .minecraftVersion("1.19.0/1.19.2") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v534.V534_CODEC.toBuilder() .minecraftVersion("1.19.10/1.19.11") .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** diff --git a/pom.xml b/pom.xml index 1d99d93e0..c5b293c43 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.6-SNAPSHOT + 2.0.7-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From ef8130e7c081a19d9ec5ba9c0c58b0584f5e6b0b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 9 Aug 2022 20:31:29 -0400 Subject: [PATCH 124/290] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49aba79ac..42979bdbe 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.10/1.19.11 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From 25a18a2e4f77adde68e61a7dbdf8039f9ef6ea33 Mon Sep 17 00:00:00 2001 From: David Choo Date: Tue, 9 Aug 2022 21:35:26 -0400 Subject: [PATCH 125/290] Fix maps not loading in Bedrock (#3218) --- .../main/java/org/geysermc/geyser/level/BedrockMapIcon.java | 5 +++-- .../protocol/java/level/JavaMapItemDataTranslator.java | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java index 9f1212875..9bb317996 100644 --- a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java @@ -33,7 +33,7 @@ public enum BedrockMapIcon { ICON_ITEM_FRAME(MapIconType.GREEN_ARROW, 7), ICON_RED_ARROW(MapIconType.RED_ARROW, 2), ICON_BLUE_ARROW(MapIconType.BLUE_ARROW, 3), - ICON_TREASURE_MARKER(MapIconType.TREASURE_MARKER, 4), + ICON_WHITE_CROSS(MapIconType.WHITE_CROSS, 4, 0, 0, 0), // Doesn't exist on Bedrock, replaced with a black cross ICON_RED_POINTER(MapIconType.RED_POINTER, 5), ICON_WHITE_CIRCLE(MapIconType.WHITE_CIRCLE, 6), ICON_SMALL_WHITE_CIRCLE(MapIconType.SMALL_WHITE_CIRCLE, 13), @@ -54,7 +54,8 @@ public enum BedrockMapIcon { ICON_BROWN_BANNER(MapIconType.BROWN_BANNER, 13, 131, 84, 50), ICON_GREEN_BANNER(MapIconType.GREEN_BANNER, 13, 94, 124, 22), ICON_RED_BANNER(MapIconType.RED_BANNER, 13, 176, 46, 38), - ICON_BLACK_BANNER(MapIconType.BLACK_BANNER, 13, 29, 29, 33); + ICON_BLACK_BANNER(MapIconType.BLACK_BANNER, 13, 29, 29, 33), + ICON_TREASURE_MARKER(MapIconType.TREASURE_MARKER, 4); private static final BedrockMapIcon[] VALUES = values(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index eb658aa54..495455958 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.data.game.level.map.MapData; import com.github.steveice10.mc.protocol.data.game.level.map.MapIcon; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundMapItemDataPacket; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.MapDecoration; import com.nukkitx.protocol.bedrock.data.MapTrackedObject; import org.geysermc.geyser.session.GeyserSession; @@ -48,6 +49,7 @@ public class JavaMapItemDataTranslator extends PacketTranslator Date: Wed, 10 Aug 2022 16:09:55 -0400 Subject: [PATCH 126/290] Fix sending forms with floodgate for 1.19.20 (#3217) * Fix sending forms with floodgate * Comment about 1.19.20 * Swapped if-else Co-authored-by: Tim203 --- .../java/JavaCustomPayloadTranslator.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index 13ace5e23..e25285114 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -72,12 +72,19 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { - byte[] raw = response.getBytes(StandardCharsets.UTF_8); - byte[] finalData = new byte[raw.length + 2]; + byte[] finalData; + if (response == null) { + // Response data can be null as of 1.19.20 (same behaviour as empty response data) + // Only need to send the form id + finalData = new byte[]{data[1], data[2]}; + } else { + byte[] raw = response.getBytes(StandardCharsets.UTF_8); + finalData = new byte[raw.length + 2]; - finalData[0] = data[1]; - finalData[1] = data[2]; - System.arraycopy(raw, 0, finalData, 2, raw.length); + finalData[0] = data[1]; + finalData[1] = data[2]; + System.arraycopy(raw, 0, finalData, 2, raw.length); + } session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData)); }); From 678e285cd4a78fa9f2f513c299e02f6c6d62753f Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 10 Aug 2022 22:12:05 +0200 Subject: [PATCH 127/290] Bump Cumulus version to 1.1.1 --- common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/pom.xml b/common/pom.xml index 0b1153230..67b77a98a 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ org.geysermc.cumulus cumulus - 1.1 + 1.1.1 com.google.code.gson From 8b57a7c6918893179e097c6f8bc2296e63581b99 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 10 Aug 2022 22:27:24 +0200 Subject: [PATCH 128/290] Use StandardCharsets instead of Charsets --- .../floodgate/pluginmessage/PluginMessageChannels.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java index f06c0f9da..58281dec8 100644 --- a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java +++ b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java @@ -25,7 +25,7 @@ package org.geysermc.floodgate.pluginmessage; -import com.google.common.base.Charsets; +import java.nio.charset.StandardCharsets; public final class PluginMessageChannels { public static final String SKIN = "floodgate:skin"; @@ -35,7 +35,7 @@ public final class PluginMessageChannels { private static final byte[] FLOODGATE_REGISTER_DATA = String.join("\0", SKIN, FORM, TRANSFER, PACKET) - .getBytes(Charsets.UTF_8); + .getBytes(StandardCharsets.UTF_8); /** * Get the prebuilt register data as a byte array From 2a2e63e51961b82a066fcd70d157fe84b3b46c0a Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 10 Aug 2022 17:39:48 -0400 Subject: [PATCH 129/290] Explicitly set gson dependency in common --- build-logic/src/main/kotlin/Versions.kt | 1 + common/build.gradle.kts | 1 + 2 files changed, 2 insertions(+) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 38ef82d26..d9af831f0 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -28,6 +28,7 @@ object Versions { const val fastutilVersion = "8.5.2" const val nettyVersion = "4.1.66.Final" const val guavaVersion = "29.0-jre" + const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" const val protocolVersion = "0bd459f" diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 205b20c0e..6c1414105 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,3 +1,4 @@ dependencies { api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) + api("com.google.code.gson", "gson", Versions.gsonVersion) } \ No newline at end of file From 50ea5eac9a44f443bccf68c7bd5a30efe37b1e7f Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 10 Aug 2022 15:05:59 -0700 Subject: [PATCH 130/290] Set baby if armor stand is small for OptionalPack (#3210) --- .../org/geysermc/geyser/entity/type/living/ArmorStandEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index c368deb6d..8ab882f4b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -167,6 +167,7 @@ public class ArmorStandEntity extends LivingEntity { // But if given a resource pack, then we can use these values to control armor stand visual properties setFlag(EntityFlag.ANGRY, (xd & 0x04) != 0x04); // Has arms setFlag(EntityFlag.ADMIRING, (xd & 0x08) == 0x08); // Has no baseplate + setFlag(EntityFlag.BABY, isSmall); // Is small (for setting head scale) } public void setHeadRotation(EntityMetadata entityMetadata) { From 80588a07bd39314cafab6cf84a779ab022ef6ae0 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 9 Aug 2022 20:06:53 +0200 Subject: [PATCH 131/290] Initial API changes --- api/base/build.gradle.kts | 6 ++- .../java/org/geysermc/api/GeyserApiBase.java | 50 ++++++++++++------- .../geysermc/api/connection/Connection.java | 21 ++++++-- .../org/geysermc/geyser/api/GeyserApi.java | 2 +- .../network/session/GeyserSession.java | 2 +- .../java/org/geysermc/geyser/GeyserImpl.java | 12 +++-- .../geyser/command/defaults/ListCommand.java | 2 +- .../geyser/scoreboard/ScoreboardUpdater.java | 2 +- .../geyser/session/GeyserSession.java | 16 +++--- .../geyser/session/cache/TagCache.java | 4 +- .../geyser/skin/FloodgateSkinUploader.java | 2 +- .../inventory/InventoryTranslator.java | 4 +- .../inventory/PlayerInventoryTranslator.java | 2 +- ...BedrockInventoryTransactionTranslator.java | 2 +- ...SetLocalPlayerAsInitializedTranslator.java | 4 +- .../player/BedrockMovePlayerTranslator.java | 2 +- .../JavaContainerSetContentTranslator.java | 2 +- .../JavaContainerSetSlotTranslator.java | 2 +- 18 files changed, 87 insertions(+), 50 deletions(-) diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index d7500fdaa..c9ddf4489 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -1 +1,5 @@ -provided("net.kyori", "event-api", Versions.eventVersion) \ No newline at end of file +dependencies { + api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) +} + +provided("net.kyori", "event-api", Versions.eventVersion) diff --git a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java index e5105b1be..e9957e21c 100644 --- a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java +++ b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java @@ -25,9 +25,12 @@ package org.geysermc.api; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.connection.Connection; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.util.FormBuilder; import java.util.List; import java.util.UUID; @@ -37,52 +40,65 @@ import java.util.UUID; */ public interface GeyserApiBase { /** - * Gets the session from the given UUID, if applicable. The player must be logged in to the Java server + * Gets the connection from the given UUID, if applicable. The player must be logged in to the Java server * for this to return a non-null value. * - * @param uuid the UUID of the session - * @return the session from the given UUID, if applicable + * @param uuid the UUID of the connection + * @return the connection from the given UUID, if applicable */ @Nullable Connection connectionByUuid(@NonNull UUID uuid); /** - * Gets the session from the given - * XUID, if applicable. + * Gets the connection from the given XUID, if applicable. This method only works for online connections. * * @param xuid the XUID of the session - * @return the session from the given UUID, if applicable + * @return the connection from the given UUID, if applicable */ @Nullable Connection connectionByXuid(@NonNull String xuid); /** - * Gets the session from the given - * name, if applicable. + * Method to determine if the given online player is a Bedrock player. * - * @param name the uuid of the session - * @return the session from the given name, if applicable + * @param uuid the uuid of the online player + * @return true if the given online player is a Bedrock player */ - @Nullable - Connection connectionByName(@NonNull String name); + boolean isBedrockPlayer(@NonNull UUID uuid); + + boolean sendForm(UUID uuid, Form form); + + boolean sendForm(UUID uuid, FormBuilder formBuilder); + + boolean transfer(UUID uuid, String address, int port); + /** - * Gets all the online sessions. - * - * @return all the online sessions + * Returns all the online connections. */ @NonNull List onlineConnections(); /** - * @return the major API version. Bumped whenever a significant breaking change or feature addition is added. + * Returns the amount of online connections. + */ + int onlineConnectionsCount(); + + /** + * Returns the prefix used by Floodgate. Will be null when the auth-type isn't Floodgate. + */ + @MonotonicNonNull + String usernamePrefix(); + + /** + * Returns the major API version. Bumped whenever a significant breaking change or feature addition is added. */ default int majorApiVersion() { return 1; } /** - * @return the minor API version. May be bumped for new API additions. + * Returns the minor API version. May be bumped for new API additions. */ default int minorApiVersion() { return 0; diff --git a/api/base/src/main/java/org/geysermc/api/connection/Connection.java b/api/base/src/main/java/org/geysermc/api/connection/Connection.java index fc6cdae20..db09149e2 100644 --- a/api/base/src/main/java/org/geysermc/api/connection/Connection.java +++ b/api/base/src/main/java/org/geysermc/api/connection/Connection.java @@ -25,6 +25,7 @@ package org.geysermc.api.connection; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.common.value.qual.IntRange; @@ -33,27 +34,37 @@ import java.util.UUID; /** * Represents a player connection. */ -@NonNull public interface Connection { /** - * Gets the name of the connection. + * Gets the bedrock name of the connection. * - * @return the name of the connection + * @return the bedrock name of the connection */ - String name(); + @NonNull + String bedrockUsername(); + + /** + * Gets the java name of the connection. + * + * @return the java name of the connection + */ + @MonotonicNonNull + String javaUsername(); /** * Gets the {@link UUID} of the connection. * * @return the UUID of the connection */ - UUID uuid(); + @MonotonicNonNull + UUID javaUuid(); /** * Gets the XUID of the connection. * * @return the XUID of the connection */ + @NonNull String xuid(); /** diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index 16bfe7070..9b584b985 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -59,7 +59,7 @@ public interface GeyserApi extends GeyserApiBase { * {@inheritDoc} */ @Override - @Nullable GeyserConnection connectionByName(@NonNull String name); + @Nullable GeyserConnection connectionByUsername(@NonNull String username); /** * {@inheritDoc} diff --git a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 21aa35efc..258787e78 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -128,7 +128,7 @@ public class GeyserSession { } public String getName() { - return this.handle.name(); + return this.handle.bedrockUsername(); } public boolean isConsole() { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 276c5328d..67a144f36 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -465,9 +465,10 @@ public class GeyserImpl implements GeyserApi { } @Override - public @Nullable GeyserSession connectionByName(@NonNull String name) { + public @Nullable GeyserSession connectionByUsername(@NonNull String username) { for (GeyserSession session : sessionManager.getAllSessions()) { - if (session.name().equals(name) || session.getProtocol().getProfile().getName().equals(name)) { + if (session.bedrockUsername().equals(username) || session.getProtocol().getProfile().getName().equals( + username)) { return session; } } @@ -477,7 +478,12 @@ public class GeyserImpl implements GeyserApi { @Override public @NonNull List onlineConnections() { - return this.sessionManager.getAllSessions(); + return sessionManager.getAllSessions(); + } + + @Override + public int onlineConnectionsCount() { + return sessionManager.size(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java index f911e431e..90446fbb6 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java @@ -47,7 +47,7 @@ public class ListCommand extends GeyserCommand { public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) { String message = GeyserLocale.getPlayerLocaleString("geyser.commands.list.message", sender.locale(), geyser.getSessionManager().size(), - geyser.getSessionManager().getAllSessions().stream().map(GeyserSession::name).collect(Collectors.joining(" "))); + geyser.getSessionManager().getAllSessions().stream().map(GeyserSession::bedrockUsername).collect(Collectors.joining(" "))); sender.sendMessage(message); } diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java index 45ae7eff2..fed3054b4 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java @@ -118,7 +118,7 @@ public final class ScoreboardUpdater extends Thread { FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD; geyser.getLogger().info( - GeyserLocale.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached.log", session.name(), threshold, pps) + + GeyserLocale.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached.log", session.bedrockUsername(), threshold, pps) + GeyserLocale.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached", (millisBetweenUpdates / 1000.0)) ); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 031d8f7f5..c8ae4792b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -735,7 +735,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { try { service.login(); } catch (RequestException e) { - geyser.getLogger().error("Error while attempting to use refresh token for " + name() + "!", e); + geyser.getLogger().error("Error while attempting to use refresh token for " + bedrockUsername() + "!", e); return Boolean.FALSE; } @@ -747,7 +747,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } protocol = new MinecraftProtocol(profile, service.getAccessToken()); - geyser.saveRefreshToken(name(), service.getRefreshToken()); + geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); return Boolean.TRUE; }).whenComplete((successful, ex) -> { if (this.closed) { @@ -838,7 +838,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { connectDownstream(); // Save our refresh token for later use - geyser.saveRefreshToken(name(), service.getRefreshToken()); + geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); return true; } } @@ -1071,7 +1071,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { try { runnable.run(); } catch (Throwable e) { - geyser.getLogger().error("Error thrown in " + this.name() + "'s event loop!", e); + geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } }); } @@ -1084,7 +1084,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { try { runnable.run(); } catch (Throwable e) { - geyser.getLogger().error("Error thrown in " + this.name() + "'s event loop!", e); + geyser.getLogger().error("Error thrown in " + this.bedrockUsername() + "'s event loop!", e); } }, duration, timeUnit); } @@ -1326,13 +1326,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } @Override - public String name() { + public String bedrockUsername() { return authData.name(); } @Override - public UUID uuid() { - return authData.uuid(); + public UUID javaUuid() { + } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index ac0c93204..9cd5b2ef6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -89,7 +89,7 @@ public class TagCache { boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0; session.setEmulatePost1_18Logic(emulatePost1_18Logic); if (logger.isDebug()) { - logger.debug("Emulating post 1.18 block predication logic for " + session.name() + "? " + emulatePost1_18Logic); + logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic); } Map itemTags = packet.getTags().get("minecraft:item"); @@ -104,7 +104,7 @@ public class TagCache { boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1; session.setEmulatePost1_13Logic(emulatePost1_13Logic); if (logger.isDebug()) { - logger.debug("Emulating post 1.13 villager logic for " + session.name() + "? " + emulatePost1_13Logic); + logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic); } } diff --git a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java index 4d0e98444..7b6dacd16 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java @@ -114,7 +114,7 @@ public final class FloodgateSkinUploader { if (session != null) { if (!node.get("success").asBoolean()) { - logger.info("Failed to upload skin for " + session.name()); + logger.info("Failed to upload skin for " + session.bedrockUsername()); return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index 6f4ca7ee4..fc442c329 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -201,7 +201,7 @@ public abstract class InventoryTranslator { TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { if (session.getGeyser().getConfig().isDebugMode()) { - session.getGeyser().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.name()); + session.getGeyser().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.bedrockUsername()); dumpStackRequestDetails(session, inventory, transferAction.getSource(), transferAction.getDestination()); } return rejectRequest(request); @@ -292,7 +292,7 @@ public abstract class InventoryTranslator { if (!(checkNetId(session, inventory, source) && checkNetId(session, inventory, destination))) { if (session.getGeyser().getConfig().isDebugMode()) { - session.getGeyser().getLogger().error("DEBUG: About to reject SWAP request made by " + session.name()); + session.getGeyser().getLogger().error("DEBUG: About to reject SWAP request made by " + session.bedrockUsername()); dumpStackRequestDetails(session, inventory, source, destination); } return rejectRequest(request); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index e2349e5a5..ee7d6a7c6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -371,7 +371,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } } default -> { - session.getGeyser().getLogger().error("Unknown crafting state induced by " + session.name()); + session.getGeyser().getLogger().error("Unknown crafting state induced by " + session.bedrockUsername()); return rejectRequest(request); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 815456132..521adb687 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -546,7 +546,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 300) { - session.getGeyser().getLogger().debug(ChatColor.RED + session.name() + " moved too quickly." + + session.getGeyser().getLogger().debug(ChatColor.RED + session.bedrockUsername() + " moved too quickly." + " current position: " + currentPosition + ", new position: " + newPosition); return false; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java index 0775028fe..619825338 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java @@ -48,7 +48,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator inventorySize) { GeyserImpl geyser = session.getGeyser(); - geyser.getLogger().warning("ClientboundContainerSetContentPacket sent to " + session.name() + geyser.getLogger().warning("ClientboundContainerSetContentPacket sent to " + session.bedrockUsername() + " that exceeds inventory size!"); if (geyser.getConfig().isDebugMode()) { geyser.getLogger().debug(packet); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java index aef8cf8b2..9a5569392 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java @@ -76,7 +76,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator= inventory.getSize()) { GeyserImpl geyser = session.getGeyser(); - geyser.getLogger().warning("ClientboundContainerSetSlotPacket sent to " + session.name() + geyser.getLogger().warning("ClientboundContainerSetSlotPacket sent to " + session.bedrockUsername() + " that exceeds inventory size!"); if (geyser.getConfig().isDebugMode()) { geyser.getLogger().debug(packet); From ab6e0d1e168d46e8883477998b1acc2cd17cb5d9 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 12 Aug 2022 01:01:26 +0200 Subject: [PATCH 132/290] Some more API changes --- .../java/org/geysermc/api/GeyserApiBase.java | 30 ++++- .../geysermc/api/connection/Connection.java | 78 +++++++++--- .../geysermc/api/util/BedrockPlatform.java | 70 +++++++++++ .../java/org/geysermc/api/util/InputMode.java | 46 +++++++ .../java/org/geysermc/api/util/UiProfile.java | 42 +++++++ .../java/org/geysermc/geyser/GeyserImpl.java | 45 ++++++- .../type/player/SessionPlayerEntity.java | 2 +- .../geyser/session/GeyserSession.java | 112 ++++++++++++------ .../geyser/session/SessionManager.java | 11 ++ 9 files changed, 374 insertions(+), 62 deletions(-) create mode 100644 api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java create mode 100644 api/base/src/main/java/org/geysermc/api/util/InputMode.java create mode 100644 api/base/src/main/java/org/geysermc/api/util/UiProfile.java diff --git a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java index e9957e21c..a845e37fd 100644 --- a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java +++ b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java @@ -28,6 +28,7 @@ package org.geysermc.api; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.common.value.qual.IntRange; import org.geysermc.api.connection.Connection; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; @@ -66,11 +67,34 @@ public interface GeyserApiBase { */ boolean isBedrockPlayer(@NonNull UUID uuid); - boolean sendForm(UUID uuid, Form form); + /** + * Sends a form to the given connection and opens it. + * + * @param uuid the uuid of the connection to open it on + * @param form the form to send + * @return whether the form was successfully sent + */ + boolean sendForm(@NonNull UUID uuid, @NonNull Form form); - boolean sendForm(UUID uuid, FormBuilder formBuilder); + /** + * Sends a form to the given connection and opens it. + * + * @param uuid the uuid of the connection to open it on + * @param formBuilder the formBuilder to send + * @return whether the form was successfully sent + */ + boolean sendForm(@NonNull UUID uuid, @NonNull FormBuilder formBuilder); - boolean transfer(UUID uuid, String address, int port); + /** + * Transfer the given connection to a server. A Bedrock player can successfully transfer to the same server they are + * currently playing on. + * + * @param uuid the uuid of the connection + * @param address the address of the server + * @param port the port of the server + * @return true if the transfer was a success + */ + boolean transfer(@NonNull UUID uuid, @NonNull String address, @IntRange(from = 0, to = 65535) int port); /** diff --git a/api/base/src/main/java/org/geysermc/api/connection/Connection.java b/api/base/src/main/java/org/geysermc/api/connection/Connection.java index db09149e2..1cd7a9d13 100644 --- a/api/base/src/main/java/org/geysermc/api/connection/Connection.java +++ b/api/base/src/main/java/org/geysermc/api/connection/Connection.java @@ -28,6 +28,11 @@ package org.geysermc.api.connection; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.common.value.qual.IntRange; +import org.geysermc.api.util.BedrockPlatform; +import org.geysermc.api.util.InputMode; +import org.geysermc.api.util.UiProfile; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.util.FormBuilder; import java.util.UUID; @@ -36,43 +41,80 @@ import java.util.UUID; */ public interface Connection { /** - * Gets the bedrock name of the connection. - * - * @return the bedrock name of the connection + * Returns the bedrock name of the connection. */ - @NonNull - String bedrockUsername(); + @NonNull String bedrockUsername(); /** - * Gets the java name of the connection. - * - * @return the java name of the connection + * Returns the java name of the connection. */ @MonotonicNonNull String javaUsername(); /** - * Gets the {@link UUID} of the connection. - * - * @return the UUID of the connection + * Returns the UUID of the connection. */ @MonotonicNonNull UUID javaUuid(); /** - * Gets the XUID of the connection. - * - * @return the XUID of the connection + * Returns the XUID of the connection. */ - @NonNull - String xuid(); + @NonNull String xuid(); + + /** + * Returns the version of the Bedrock client. + */ + @NonNull String version(); + + /** + * Returns the platform that the connection is playing on. + */ + @NonNull BedrockPlatform platform(); + + /** + * Returns the language code of the connection. + */ + @NonNull String languageCode(); + + /** + * Returns the User Interface Profile of the connection. + */ + @NonNull UiProfile uiProfile(); + + /** + * Returns the Input Mode of the Bedrock client. + */ + @NonNull InputMode inputMode(); + + /** + * Returns whether the connection is linked. + * This will always return false when the auth-type isn't Floodgate. + */ + boolean isLinked(); + + /** + * Sends a form to the connection and opens it. + * + * @param form the form to send + * @return whether the form was successfully sent + */ + boolean sendForm(@NonNull Form form); + + /** + * Sends a form to the connection and opens it. + * + * @param formBuilder the formBuilder to send + * @return whether the form was successfully sent + */ + boolean sendForm(@NonNull FormBuilder formBuilder); /** * Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are * currently playing on. * - * @param address The address of the server - * @param port The port of the server + * @param address the address of the server + * @param port the port of the server * @return true if the transfer was a success */ boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port); diff --git a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java new file mode 100644 index 000000000..d66077a87 --- /dev/null +++ b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019-2022 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.api.util; + +public enum BedrockPlatform { + UNKNOWN("Unknown"), + GOOGLE("Android"), + IOS("iOS"), + OSX("macOS"), + AMAZON("Amazon"), + GEARVR("Gear VR"), + HOLOLENS("Hololens"), + UWP("Windows 10"), + WIN32("Windows x86"), + DEDICATED("Dedicated"), + TVOS("Apple TV"), + PS4("PS4"), + NX("Switch"), + XBOX("Xbox One"), + WINDOWS_PHONE("Windows Phone"); + + private static final BedrockPlatform[] VALUES = values(); + + private final String displayName; + + BedrockPlatform(String displayName) { + this.displayName = displayName; + } + + /** + * Get the BedrockPlatform from the identifier. + * + * @param id the BedrockPlatform identifier + * @return The BedrockPlatform or {@link #UNKNOWN} if the platform wasn't found + */ + public static BedrockPlatform fromId(int id) { + return id < VALUES.length ? VALUES[id] : VALUES[0]; + } + + /** + * @return friendly display name of platform. + */ + @Override + public String toString() { + return displayName; + } +} diff --git a/api/base/src/main/java/org/geysermc/api/util/InputMode.java b/api/base/src/main/java/org/geysermc/api/util/InputMode.java new file mode 100644 index 000000000..eadb457ab --- /dev/null +++ b/api/base/src/main/java/org/geysermc/api/util/InputMode.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 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.api.util; + +public enum InputMode { + UNKNOWN, + KEYBOARD_MOUSE, + TOUCH, + CONTROLLER, + VR; + + private static final InputMode[] VALUES = values(); + + /** + * Get the InputMode from the identifier. + * + * @param id the InputMode identifier + * @return The InputMode or {@link #UNKNOWN} if the mode wasn't found + */ + public static InputMode fromId(int id) { + return VALUES.length > id ? VALUES[id] : VALUES[0]; + } +} \ No newline at end of file diff --git a/api/base/src/main/java/org/geysermc/api/util/UiProfile.java b/api/base/src/main/java/org/geysermc/api/util/UiProfile.java new file mode 100644 index 000000000..c28ff869c --- /dev/null +++ b/api/base/src/main/java/org/geysermc/api/util/UiProfile.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2022 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.api.util; + +public enum UiProfile { + CLASSIC, POCKET; + + private static final UiProfile[] VALUES = values(); + + /** + * Get the UiProfile from the identifier. + * + * @param id the UiProfile identifier + * @return The UiProfile or {@link #CLASSIC} if the profile wasn't found + */ + public static UiProfile fromId(int id) { + return VALUES.length > id ? VALUES[id] : VALUES[0]; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 67a144f36..94a2b4304 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -41,10 +41,13 @@ import io.netty.util.internal.SystemPropertyUtil; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; import org.geysermc.common.PlatformType; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -486,6 +489,11 @@ public class GeyserImpl implements GeyserApi { return sessionManager.size(); } + @Override + public @MonotonicNonNull String usernamePrefix() { + return null; + } + @Override public @Nullable GeyserSession connectionByUuid(@NonNull UUID uuid) { return this.sessionManager.getSessions().get(uuid); @@ -493,13 +501,38 @@ public class GeyserImpl implements GeyserApi { @Override public @Nullable GeyserSession connectionByXuid(@NonNull String xuid) { - for (GeyserSession session : sessionManager.getAllSessions()) { - if (session.xuid().equals(xuid)) { - return session; - } - } + return sessionManager.sessionByXuid(xuid); + } - return null; + @Override + public boolean isBedrockPlayer(@NonNull UUID uuid) { + return connectionByUuid(uuid) != null; + } + + @Override + public boolean sendForm(@NonNull UUID uuid, @NonNull Form form) { + Objects.requireNonNull(uuid); + Objects.requireNonNull(form); + GeyserSession session = connectionByUuid(uuid); + if (session == null) { + return false; + } + return session.sendForm(form); + } + + @Override + public boolean sendForm(@NonNull UUID uuid, @NonNull FormBuilder formBuilder) { + return sendForm(uuid, formBuilder.build()); + } + + @Override + public boolean transfer(@NonNull UUID uuid, @NonNull String address, int port) { + Objects.requireNonNull(uuid); + GeyserSession session = connectionByUuid(uuid); + if (session == null) { + return false; + } + return session.transfer(address, port); } public void shutdown() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index f16f46e2e..7a5d34973 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -73,7 +73,7 @@ public class SessionPlayerEntity extends PlayerEntity { private int fakeTradeXp; public SessionPlayerEntity(GeyserSession session) { - super(session, -1, 1, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "unknown", null); + super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null); valid = true; } diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index c8ae4792b..f67d8d92d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -91,6 +91,9 @@ import lombok.Setter; import lombok.experimental.Accessors; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.common.value.qual.IntRange; +import org.geysermc.api.util.BedrockPlatform; +import org.geysermc.api.util.InputMode; +import org.geysermc.api.util.UiProfile; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; @@ -136,7 +139,6 @@ import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MathUtils; -import javax.annotation.Nonnull; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -151,13 +153,13 @@ import java.util.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements GeyserConnection, GeyserCommandSource { - private final @Nonnull GeyserImpl geyser; - private final @Nonnull UpstreamSession upstream; + private final @NonNull GeyserImpl geyser; + private final @NonNull UpstreamSession upstream; /** * The loop where all packets and ticking is processed to prevent concurrency issues. * If this is manually called, ensure that any exceptions are properly handled. */ - private final @Nonnull EventLoop eventLoop; + private final @NonNull EventLoop eventLoop; private TcpSession downstream; @Setter private AuthData authData; @@ -1326,33 +1328,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } @Override - public String bedrockUsername() { - return authData.name(); - } - - @Override - public UUID javaUuid() { - - } - - @Override - public String xuid() { - return authData.xuid(); - } - - @SuppressWarnings("ConstantConditions") // Need to enforce the parameter annotations - @Override - public boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port) { - if (address == null || address.isBlank()) { - throw new IllegalArgumentException("Server address cannot be null or blank"); - } else if (port < 0 || port > 65535) { - throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port); - } - TransferPacket transferPacket = new TransferPacket(); - transferPacket.setAddress(address); - transferPacket.setPort(port); - sendUpstreamPacket(transferPacket); - return true; + public String name() { + return null; } @Override @@ -1405,12 +1382,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return this.upstream.getAddress(); } - public void sendForm(Form form) { + public boolean sendForm(@NonNull Form form) { formCache.showForm(form); + return true; } - public void sendForm(FormBuilder formBuilder) { + public boolean sendForm(@NonNull FormBuilder formBuilder) { formCache.showForm(formBuilder.build()); + return true; } /** @@ -1765,7 +1744,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { * * @param statistics Updated statistics values */ - public void updateStatistics(@Nonnull Object2IntMap statistics) { + public void updateStatistics(@NonNull Object2IntMap statistics) { if (this.statistics.isEmpty()) { // Initialize custom statistics to 0, so that they appear in the form for (CustomStatistic customStatistic : CustomStatistic.values()) { @@ -1851,4 +1830,69 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public MinecraftCodecHelper getCodecHelper() { return (MinecraftCodecHelper) this.downstream.getCodecHelper(); } + + @Override + public String bedrockUsername() { + return authData.name(); + } + + @Override + public @MonotonicNonNull String javaUsername() { + return playerEntity.getUsername(); + } + + @Override + public UUID javaUuid() { + return playerEntity.getUuid(); + } + + @Override + public String xuid() { + return authData.xuid(); + } + + @Override + public @NonNull String version() { + return clientData.getGameVersion(); + } + + @Override + public @NonNull BedrockPlatform platform() { + return BedrockPlatform.values()[clientData.getDeviceOs().ordinal()]; //todo + } + + @Override + public @NonNull String languageCode() { + return locale(); + } + + @Override + public @NonNull UiProfile uiProfile() { + return UiProfile.values()[clientData.getUiProfile().ordinal()]; //todo + } + + @Override + public @NonNull InputMode inputMode() { + return InputMode.values()[clientData.getCurrentInputMode().ordinal()]; //todo + } + + @Override + public boolean isLinked() { + return false; //todo + } + + @SuppressWarnings("ConstantConditions") // Need to enforce the parameter annotations + @Override + public boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port) { + if (address == null || address.isBlank()) { + throw new IllegalArgumentException("Server address cannot be null or blank"); + } else if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port); + } + TransferPacket transferPacket = new TransferPacket(); + transferPacket.setAddress(address); + transferPacket.setPort(port); + sendUpstreamPacket(transferPacket); + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index fc6c37356..2660f54b1 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.session; import com.google.common.collect.ImmutableList; import lombok.AccessLevel; import lombok.Getter; +import lombok.NonNull; import org.geysermc.geyser.text.GeyserLocale; import java.util.*; @@ -67,6 +68,16 @@ public final class SessionManager { } } + public GeyserSession sessionByXuid(@NonNull String xuid) { + Objects.requireNonNull(xuid); + for (GeyserSession session : sessions.values()) { + if (session.xuid().equals(xuid)) { + return session; + } + } + return null; + } + /** * Creates a new, immutable list containing all pending and active sessions. */ From 33af9e094c9b3b7844e57c67c25b8c5b3577c127 Mon Sep 17 00:00:00 2001 From: David Choo Date: Fri, 12 Aug 2022 22:25:07 -0400 Subject: [PATCH 133/290] Fix missing cool down indicator when attacking mobs (#3230) --- .../BedrockInventoryTransactionTranslator.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 24c046ef2..7c2a48137 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -54,6 +54,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -62,10 +63,7 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.BlockUtils; -import org.geysermc.geyser.util.EntityUtils; -import org.geysermc.geyser.util.InteractionResult; -import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.geyser.util.*; import java.util.List; import java.util.concurrent.TimeUnit; @@ -468,6 +466,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sat, 13 Aug 2022 22:48:12 +0200 Subject: [PATCH 134/290] Fixed building and switched event library --- api/base/build.gradle.kts | 3 +- .../org/geysermc/geyser/api/GeyserApi.java | 6 - .../geysermc/geyser/api/event/EventBus.java | 63 +---------- ...{Cancellable.java => EventSubscriber.java} | 26 ++--- .../geyser/api/event/EventSubscription.java | 82 -------------- .../geyser/api/event/ExtensionEventBus.java | 31 +----- ...ent.java => ExtensionEventSubscriber.java} | 15 +-- .../geysermc/geyser/api/event/Subscribe.java | 103 ----------------- .../api/event/connection/ConnectionEvent.java | 2 +- .../downstream/ServerDefineCommandsEvent.java | 2 +- .../GeyserDefineCustomItemsEvent.java | 29 ++--- .../GeyserLoadResourcePacksEvent.java | 2 +- .../lifecycle/GeyserPostInitializeEvent.java | 2 +- .../lifecycle/GeyserPreInitializeEvent.java | 2 +- .../event/lifecycle/GeyserShutdownEvent.java | 2 +- build-logic/src/main/kotlin/Versions.kt | 2 +- core/build.gradle.kts | 3 - .../java/org/geysermc/geyser/GeyserImpl.java | 12 -- .../event/AbstractEventSubscription.java | 68 ------------ .../event/GeneratedEventSubscription.java | 60 ---------- .../geysermc/geyser/event/GeyserEventBus.java | 105 ++++-------------- ...iption.java => GeyserEventSubscriber.java} | 35 ++---- .../event/type/DefineCustomItemsEvent.java | 85 ++++++++++++++ .../event/GeyserExtensionEventBus.java | 72 +++++------- .../populator/ItemRegistryPopulator.java | 3 +- 25 files changed, 193 insertions(+), 622 deletions(-) rename api/geyser/src/main/java/org/geysermc/geyser/api/event/{Cancellable.java => EventSubscriber.java} (74%) delete mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java rename api/geyser/src/main/java/org/geysermc/geyser/api/event/{Event.java => ExtensionEventSubscriber.java} (85%) delete mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/Subscribe.java delete mode 100644 core/src/main/java/org/geysermc/geyser/event/AbstractEventSubscription.java delete mode 100644 core/src/main/java/org/geysermc/geyser/event/GeneratedEventSubscription.java rename core/src/main/java/org/geysermc/geyser/event/{BaseEventSubscription.java => GeyserEventSubscriber.java} (55%) create mode 100644 core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index c9ddf4489..03f08c6d2 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -1,5 +1,4 @@ dependencies { api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) + api("org.geysermc.event", "events", Versions.eventsVersion) } - -provided("net.kyori", "event-api", Versions.eventVersion) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index 9b584b985..82f0566fe 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -55,12 +55,6 @@ public interface GeyserApi extends GeyserApiBase { @Override @Nullable GeyserConnection connectionByXuid(@NonNull String xuid); - /** - * {@inheritDoc} - */ - @Override - @Nullable GeyserConnection connectionByUsername(@NonNull String username); - /** * {@inheritDoc} */ diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java index b13f12300..c42698d47 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java @@ -26,71 +26,18 @@ package org.geysermc.geyser.api.event; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; +import org.geysermc.event.bus.OwnedEventBus; import org.geysermc.geyser.api.extension.Extension; import java.util.Set; -import java.util.function.Consumer; /** * Represents a bus capable of subscribing * or "listening" to events and firing them. */ -public interface EventBus { - - /** - * Subscribes to the given event see {@link EventSubscription}. - * - * The difference between this method and {@link ExtensionEventBus#subscribe(Class, Consumer)} - * is that this method takes in an extension parameter which allows for - * the event to be unsubscribed upon extension disable and reloads. - * - * @param extension the extension to subscribe the event to - * @param eventClass the class of the event - * @param consumer the consumer for handling the event - * @param the event class - * @return the event subscription - */ +public interface EventBus extends OwnedEventBus> { + @Override @NonNull - EventSubscription subscribe(@NonNull Extension extension, @NonNull Class eventClass, @NonNull Consumer consumer); - - /** - * Unsubscribes the given {@link EventSubscription}. - * - * @param subscription the event subscription - */ - void unsubscribe(@NonNull EventSubscription subscription); - - /** - * Registers events for the given listener. - * - * @param extension the extension registering the event - * @param eventHolder the listener - */ - void register(@NonNull Extension extension, @NonNull Object eventHolder); - - /** - * Unregisters all events from a given {@link Extension}. - * - * @param extension the extension - */ - void unregisterAll(@NonNull Extension extension); - - /** - * Fires the given {@link Event} and returns the result. - * - * @param event the event to fire - * - * @return true if the event successfully fired - */ - boolean fire(@NonNull Event event); - - /** - * Gets the subscriptions for the given event class. - * - * @param eventClass the event class - * @param the value - * @return the subscriptions for the event class - */ - @NonNull - Set> subscriptions(@NonNull Class eventClass); + Set> subscribers(@NonNull Class eventClass); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Cancellable.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java similarity index 74% rename from api/geyser/src/main/java/org/geysermc/geyser/api/event/Cancellable.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java index 94d0b832d..7ce5b7883 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Cancellable.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java @@ -25,22 +25,16 @@ package org.geysermc.geyser.api.event; +import org.geysermc.event.Event; +import org.geysermc.event.subscribe.OwnedSubscriber; +import org.geysermc.geyser.api.extension.Extension; + /** - * Represents a cancellable event. + * Represents a subscribed listener to a {@link Event}. Wraps around + * the event and is capable of unsubscribing from the event or give + * information about it. + * + * @param the class of the event */ -public interface Cancellable { - - /** - * Gets if the event is cancelled. - * - * @return if the event is cancelled - */ - boolean isCancelled(); - - /** - * Cancels the event. - * - * @param cancelled if the event is cancelled - */ - void setCancelled(boolean cancelled); +public interface EventSubscriber extends OwnedSubscriber { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java deleted file mode 100644 index 9a04b697c..000000000 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscription.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.api.event; - -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.extension.Extension; - -/** - * Represents a subscribed listener to a {@link Event}. Wraps around - * the event and is capable of unsubscribing from the event or give - * information about it. - * - * @param the class of the event - */ -public interface EventSubscription { - - /** - * Gets the event class. - * - * @return the event class - */ - @NonNull - Class eventClass(); - - /** - * Gets the {@link Extension} that owns this - * event subscription. - * - * @return the extension that owns this subscription - */ - @NonNull - Extension owner(); - - /** - * Gets the post order of this event subscription. - * - * @return the post order of this event subscription - */ - Subscribe.PostOrder order(); - - /** - * Gets if this event subscription is active. - * - * @return if this event subscription is active - */ - boolean isActive(); - - /** - * Unsubscribes from this event listener - */ - void unsubscribe(); - - /** - * Invokes the given event - * - * @param event the event - */ - void invoke(@NonNull T event) throws Throwable; -} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java index db0209e5f..172c0f9de 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java @@ -26,36 +26,15 @@ package org.geysermc.geyser.api.event; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; -import java.util.function.Consumer; +import java.util.Set; /** * An {@link EventBus} with additional methods that implicitly * set the extension instance. - * */ -public interface ExtensionEventBus extends EventBus { - - /** - * Subscribes to the given event see {@link EventSubscription}. - * - * @param eventClass the class of the event - * @param consumer the consumer for handling the event - * @param the event class - * @return the event subscription - */ - @NonNull - EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer); - - /** - * Registers events for the given listener. - * - * @param eventHolder the listener - */ - void register(@NonNull Object eventHolder); - - /** - * Unregisters all events for this extension. - */ - void unregisterAll(); +public interface ExtensionEventBus extends org.geysermc.event.bus.EventBus> { + @Override + @NonNull Set> subscribers(@NonNull Class eventClass); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Event.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventSubscriber.java similarity index 85% rename from api/geyser/src/main/java/org/geysermc/geyser/api/event/Event.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventSubscriber.java index c32e1701e..9c5fffa2f 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Event.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventSubscriber.java @@ -25,17 +25,8 @@ package org.geysermc.geyser.api.event; -/** - * Represents an event. - */ -public interface Event { +import org.geysermc.event.Event; +import org.geysermc.event.subscribe.Subscriber; - /** - * Gets if the event is async. - * - * @return if the event is async - */ - default boolean isAsync() { - return false; - } +public interface ExtensionEventSubscriber extends Subscriber { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Subscribe.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/Subscribe.java deleted file mode 100644 index 488fa0ea3..000000000 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/Subscribe.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.api.event; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An annotation used to signify the given method is - * an {@link Event}. Only should be applied to methods - * where the class containing them is designated for - * events specifically. - * - * When using {@link EventBus#subscribe}, this annotation should - * not be applied whatsoever as it will have no use and potentially - * throw errors due to it being used wrongly. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface Subscribe { - - /** - * The {@link PostOrder} of the event - * - * @return the post order of the event - */ - Subscribe.PostOrder postOrder() default PostOrder.NORMAL; - - /** - * Represents the post order of an event. - */ - enum PostOrder { - - /** - * The lowest priority. Called first to - * allow for other events to customize - * the outcome - */ - FIRST(net.kyori.event.PostOrders.FIRST), - - /** - * The second lowest priority. - */ - EARLY(net.kyori.event.PostOrders.EARLY), - - /** - * Normal priority. Event is neither - * important nor unimportant - */ - NORMAL(net.kyori.event.PostOrders.NORMAL), - - /** - * The second highest priority - */ - LATE(net.kyori.event.PostOrders.LATE), - - /** - * The highest of importance! Event is called - * last and has the final say in the outcome - */ - LAST(net.kyori.event.PostOrders.LAST); - - private final int postOrder; - - PostOrder(int postOrder) { - this.postOrder = postOrder; - } - - /** - * The numerical post order value. - * - * @return numerical post order value - */ - public int postOrder() { - return this.postOrder; - } - } -} \ No newline at end of file diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java index 48f3acdb7..158f14d53 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionEvent.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.api.event.connection; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; import org.geysermc.geyser.api.connection.GeyserConnection; -import org.geysermc.geyser.api.event.Event; /** * An event that contains a {@link GeyserConnection}. diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java index 2ab1b9611..e46492b36 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/downstream/ServerDefineCommandsEvent.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.api.event.downstream; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Cancellable; import org.geysermc.geyser.api.connection.GeyserConnection; -import org.geysermc.geyser.api.event.Cancellable; import org.geysermc.geyser.api.event.connection.ConnectionEvent; import java.util.Set; diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java index 308b39d22..bfed5d534 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java @@ -25,45 +25,34 @@ package org.geysermc.geyser.api.event.lifecycle; -import com.google.common.collect.Multimap; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * Called on Geyser's startup when looking for custom items. Custom items must be registered through this event. * * This event will not be called if the "add non-Bedrock items" setting is disabled in the Geyser config. */ -public abstract class GeyserDefineCustomItemsEvent implements Event { - private final Multimap customItems; - private final List nonVanillaCustomItems; - - public GeyserDefineCustomItemsEvent(Multimap customItems, List nonVanillaCustomItems) { - this.customItems = customItems; - this.nonVanillaCustomItems = nonVanillaCustomItems; - } - +public interface GeyserDefineCustomItemsEvent extends Event { /** * Gets a multimap of all the already registered custom items indexed by the item's extended java item's identifier. * * @return a multimap of all the already registered custom items */ - public Map> getExistingCustomItems() { - return Collections.unmodifiableMap(this.customItems.asMap()); - } + Map> getExistingCustomItems(); /** * Gets the list of the already registered non-vanilla custom items. * * @return the list of the already registered non-vanilla custom items */ - public List getExistingNonVanillaCustomItems() { - return Collections.unmodifiableList(this.nonVanillaCustomItems); - } + List getExistingNonVanillaCustomItems(); /** * Registers a custom item with a base Java item. This is used to register items with custom textures and properties @@ -73,7 +62,7 @@ public abstract class GeyserDefineCustomItemsEvent implements Event { * @param customItemData the custom item data to register * @return if the item was registered */ - public abstract boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData); + boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData); /** * Registers a custom item with no base item. This is used for mods. @@ -81,5 +70,5 @@ public abstract class GeyserDefineCustomItemsEvent implements Event { * @param customItemData the custom item data to register * @return if the item was registered */ - public abstract boolean register(@NonNull NonVanillaCustomItemData customItemData); + boolean register(@NonNull NonVanillaCustomItemData customItemData); } \ No newline at end of file diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java index 0f181aedf..e9b283ecb 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; import java.nio.file.Path; import java.util.List; diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java index 94e42e075..9e88c017b 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java index fa130c883..2be0272dc 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java index a0fc2294b..f2fab901d 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java @@ -26,8 +26,8 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; import org.geysermc.geyser.api.command.CommandManager; -import org.geysermc.geyser.api.event.Event; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index d9af831f0..f7b20cca1 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -39,9 +39,9 @@ object Versions { const val mcprotocollibversion = "9f78bd5" const val packetlibVersion = "3.0" const val adventureVersion = "4.9.3" - const val eventVersion = "3.0.0" const val junitVersion = "4.13.1" const val checkerQualVersion = "3.19.0" const val cumulusVersion = "1.1.1" + const val eventsVersion = "1.0-SNAPSHOT" const val log4jVersion = "2.17.1" } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 602e0e8e3..83591e7ad 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -67,9 +67,6 @@ dependencies { implementation("net.kyori", "adventure-text-serializer-legacy", Versions.adventureVersion) implementation("net.kyori", "adventure-text-serializer-plain", Versions.adventureVersion) - // Kyori Misc - implementation("net.kyori", "event-api", Versions.eventVersion) - // Test testImplementation("junit", "junit", Versions.junitVersion) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 94a2b4304..87a40c828 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -467,18 +467,6 @@ public class GeyserImpl implements GeyserApi { this.eventBus.fire(new GeyserPostInitializeEvent(this.extensionManager, this.eventBus)); } - @Override - public @Nullable GeyserSession connectionByUsername(@NonNull String username) { - for (GeyserSession session : sessionManager.getAllSessions()) { - if (session.bedrockUsername().equals(username) || session.getProtocol().getProfile().getName().equals( - username)) { - return session; - } - } - - return null; - } - @Override public @NonNull List onlineConnections() { return sessionManager.getAllSessions(); diff --git a/core/src/main/java/org/geysermc/geyser/event/AbstractEventSubscription.java b/core/src/main/java/org/geysermc/geyser/event/AbstractEventSubscription.java deleted file mode 100644 index 69dc74935..000000000 --- a/core/src/main/java/org/geysermc/geyser/event/AbstractEventSubscription.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.event; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Accessors; -import net.kyori.event.EventSubscriber; -import org.geysermc.geyser.api.event.Event; -import org.geysermc.geyser.api.event.EventBus; -import org.geysermc.geyser.api.event.EventSubscription; -import org.geysermc.geyser.api.event.Subscribe; -import org.geysermc.geyser.api.extension.Extension; - -@Getter -@Accessors(fluent = true) -@RequiredArgsConstructor -public abstract class AbstractEventSubscription implements EventSubscription, EventSubscriber { - protected final EventBus eventBus; - protected final Class eventClass; - protected final Extension owner; - protected final Subscribe.PostOrder order; - @Getter(AccessLevel.NONE) private boolean active; - - @Override - public boolean isActive() { - return this.active; - } - - @Override - public void unsubscribe() { - if (!this.active) { - return; - } - - this.active = false; - this.eventBus.unsubscribe(this); - } - - @Override - public int postOrder() { - return this.order.postOrder(); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/event/GeneratedEventSubscription.java b/core/src/main/java/org/geysermc/geyser/event/GeneratedEventSubscription.java deleted file mode 100644 index b1ba7bf8b..000000000 --- a/core/src/main/java/org/geysermc/geyser/event/GeneratedEventSubscription.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.event; - -import lombok.Getter; -import lombok.experimental.Accessors; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; -import org.geysermc.geyser.api.event.EventBus; -import org.geysermc.geyser.api.event.Subscribe; -import org.geysermc.geyser.api.extension.Extension; - -import java.util.function.BiConsumer; - -@Getter -@Accessors(fluent = true) -public class GeneratedEventSubscription extends AbstractEventSubscription { - private final Object eventHolder; - private final BiConsumer eventConsumer; - - public GeneratedEventSubscription(EventBus eventBus, Class eventClass, Extension owner, Subscribe.PostOrder order, Object eventHolder, BiConsumer eventConsumer) { - super(eventBus, eventClass, owner, order); - - this.eventHolder = eventHolder; - this.eventConsumer = eventConsumer; - } - - @Override - public void invoke(@NonNull T event) throws Throwable { - try { - this.eventConsumer.accept(this.eventHolder, event); - } catch (Throwable ex) { - this.owner.logger().warning("Unable to fire event " + event.getClass().getSimpleName() + " with subscription " + this.eventConsumer.getClass().getSimpleName()); - ex.printStackTrace(); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java index 60e354ac9..7d0d6336d 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java @@ -25,97 +25,40 @@ package org.geysermc.geyser.event; -import net.kyori.event.EventSubscriber; -import net.kyori.event.SimpleEventBus; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; +import org.geysermc.event.bus.impl.OwnedEventBusImpl; +import org.geysermc.event.subscribe.OwnedSubscriber; +import org.geysermc.event.subscribe.Subscribe; import org.geysermc.geyser.api.event.EventBus; -import org.geysermc.geyser.api.event.EventSubscription; -import org.geysermc.geyser.api.event.Subscribe; +import org.geysermc.geyser.api.event.EventSubscriber; import org.geysermc.geyser.api.extension.Extension; -import org.lanternpowered.lmbda.LambdaFactory; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Method; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Collectors; -public class GeyserEventBus implements EventBus { - private static final MethodHandles.Lookup CALLER = MethodHandles.lookup(); +@SuppressWarnings("unchecked") +public final class GeyserEventBus extends OwnedEventBusImpl> + implements EventBus { + @Override + protected > B makeSubscription( + Extension owner, Class eventClass, Subscribe subscribe, + L listener, BiConsumer handler) { + return (B) new GeyserEventSubscriber<>( + owner, eventClass, subscribe.postOrder(), subscribe.ignoreCancelled(), listener, handler + ); + } - private final SimpleEventBus bus = new SimpleEventBus<>(Event.class); + @Override + protected > B makeSubscription( + Extension owner, Class eventClass, Consumer handler) { + return (B) new GeyserEventSubscriber<>(owner, eventClass, handler); + } + @Override @NonNull - @Override - public EventSubscription subscribe(@NonNull Extension extension, @NonNull Class eventClass, @NonNull Consumer consumer) { - return this.subscribe(eventClass, consumer, extension, Subscribe.PostOrder.NORMAL); - } - - @Override - public void unsubscribe(@NonNull EventSubscription subscription) { - this.bus.unregister((AbstractEventSubscription) subscription); - } - - @SuppressWarnings("unchecked") - @Override - public void register(@NonNull Extension extension, @NonNull Object eventHolder) { - for (Method method : eventHolder.getClass().getMethods()) { - if (!method.isAnnotationPresent(Subscribe.class)) { - continue; - } - - if (method.getParameterCount() > 1) { - continue; - } - - if (!Event.class.isAssignableFrom(method.getParameters()[0].getType())) { - continue; - } - - Subscribe subscribe = method.getAnnotation(Subscribe.class); - - try { - Class type = (Class) method.getParameters()[0].getType(); - this.subscribe(type, eventHolder, LambdaFactory.createBiConsumer(CALLER.unreflect(method)), extension, subscribe.postOrder()); - } catch (IllegalAccessException ex) { - ex.printStackTrace(); - } - } - } - - @Override - public void unregisterAll(@NonNull Extension extension) { - this.bus.unregister((Predicate>) subscriber -> extension.equals(((AbstractEventSubscription) subscriber).owner())); - } - - @Override - public boolean fire(@NonNull Event event) { - return this.bus.post(event).wasSuccessful(); - } - - @SuppressWarnings("unchecked") - @NonNull - @Override - public Set> subscriptions(@NonNull Class eventClass) { - return bus.subscribers().values() - .stream() - .filter(sub -> sub instanceof EventSubscription && ((EventSubscription) sub).eventClass().isAssignableFrom(eventClass)) - .map(sub -> ((EventSubscription) sub)) - .collect(Collectors.toSet()); - } - - private EventSubscription subscribe(Class eventClass, Consumer handler, Extension extension, Subscribe.PostOrder postOrder) { - BaseEventSubscription eventSubscription = new BaseEventSubscription<>(this, eventClass, extension, postOrder, handler); - this.bus.register(eventClass, eventSubscription); - return eventSubscription; - } - - private EventSubscription subscribe(Class eventClass, Object eventHolder, BiConsumer handler, Extension extension, Subscribe.PostOrder postOrder) { - GeneratedEventSubscription eventSubscription = new GeneratedEventSubscription<>(this, eventClass, extension, postOrder, eventHolder, handler); - this.bus.register(eventClass, eventSubscription); - return eventSubscription; + public Set> subscribers(@NonNull Class eventClass) { + return castGenericSet(super.subscribers(eventClass)); } } diff --git a/core/src/main/java/org/geysermc/geyser/event/BaseEventSubscription.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java similarity index 55% rename from core/src/main/java/org/geysermc/geyser/event/BaseEventSubscription.java rename to core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java index 79df94e5d..6fac82b96 100644 --- a/core/src/main/java/org/geysermc/geyser/event/BaseEventSubscription.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java @@ -25,34 +25,23 @@ package org.geysermc.geyser.event; -import lombok.Getter; -import lombok.experimental.Accessors; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; -import org.geysermc.geyser.api.event.EventBus; -import org.geysermc.geyser.api.event.Subscribe; +import org.geysermc.event.Event; +import org.geysermc.event.PostOrder; +import org.geysermc.event.subscribe.impl.OwnedSubscriberImpl; +import org.geysermc.geyser.api.event.ExtensionEventSubscriber; import org.geysermc.geyser.api.extension.Extension; +import java.util.function.BiConsumer; import java.util.function.Consumer; -@Getter -@Accessors(fluent = true) -public class BaseEventSubscription extends AbstractEventSubscription { - private final Consumer eventConsumer; - - public BaseEventSubscription(EventBus eventBus, Class eventClass, Extension owner, Subscribe.PostOrder order, Consumer eventConsumer) { - super(eventBus, eventClass, owner, order); - - this.eventConsumer = eventConsumer; +public final class GeyserEventSubscriber extends OwnedSubscriberImpl + implements ExtensionEventSubscriber { + GeyserEventSubscriber(Extension owner, Class eventClass, Consumer handler) { + super(owner, eventClass, handler); } - @Override - public void invoke(@NonNull T event) throws Throwable { - try { - this.eventConsumer.accept(event); - } catch (Throwable ex) { - this.owner.logger().warning("Unable to fire event " + event.getClass().getSimpleName() + " with subscription " + this.eventConsumer.getClass().getSimpleName()); - ex.printStackTrace(); - } + GeyserEventSubscriber(Extension owner, Class eventClass, PostOrder postOrder, boolean ignoreCancelled, + H handlerInstance, BiConsumer handler) { + super(owner, eventClass, postOrder, ignoreCancelled, handlerInstance, handler); } } diff --git a/core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java b/core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java new file mode 100644 index 000000000..9011bfb3a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.event.type; + +import com.google.common.collect.Multimap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomItemsEvent; +import org.geysermc.geyser.api.item.custom.CustomItemData; +import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public abstract class DefineCustomItemsEvent implements GeyserDefineCustomItemsEvent { + private final Multimap customItems; + private final List nonVanillaCustomItems; + + public DefineCustomItemsEvent(Multimap customItems, List nonVanillaCustomItems) { + this.customItems = customItems; + this.nonVanillaCustomItems = nonVanillaCustomItems; + } + + /** + * Gets a multimap of all the already registered custom items indexed by the item's extended java item's identifier. + * + * @return a multimap of all the already registered custom items + */ + @Override + public Map> getExistingCustomItems() { + return Collections.unmodifiableMap(this.customItems.asMap()); + } + + /** + * Gets the list of the already registered non-vanilla custom items. + * + * @return the list of the already registered non-vanilla custom items + */ + @Override + public List getExistingNonVanillaCustomItems() { + return Collections.unmodifiableList(this.nonVanillaCustomItems); + } + + /** + * Registers a custom item with a base Java item. This is used to register items with custom textures and properties + * based on NBT data. + * + * @param identifier the base (java) item + * @param customItemData the custom item data to register + * @return if the item was registered + */ + public abstract boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData); + + /** + * Registers a custom item with no base item. This is used for mods. + * + * @param customItemData the custom item data to register + * @return if the item was registered + */ + public abstract boolean register(@NonNull NonVanillaCustomItemData customItemData); +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java index 4104871fa..d1a647be7 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java @@ -26,62 +26,50 @@ package org.geysermc.geyser.extension.event; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.event.Event; +import org.geysermc.event.Event; +import org.geysermc.event.bus.impl.EventBusImpl; +import org.geysermc.event.subscribe.Subscribe; +import org.geysermc.event.subscribe.Subscriber; import org.geysermc.geyser.api.event.EventBus; -import org.geysermc.geyser.api.event.EventSubscription; +import org.geysermc.geyser.api.event.EventSubscriber; import org.geysermc.geyser.api.event.ExtensionEventBus; +import org.geysermc.geyser.api.event.ExtensionEventSubscriber; import org.geysermc.geyser.api.extension.Extension; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Consumer; -public record GeyserExtensionEventBus(EventBus eventBus, - Extension extension) implements ExtensionEventBus { - @NonNull +public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) implements ExtensionEventBus { @Override - public EventSubscription subscribe(@NonNull Class eventClass, @NonNull Consumer consumer) { - return this.eventBus.subscribe(this.extension, eventClass, consumer); - } - - @Override - public void register(@NonNull Object eventHolder) { - this.eventBus.register(this.extension, eventHolder); - } - - @Override - public void unregisterAll() { - this.eventBus.unregisterAll(this.extension); - } - - @NonNull - @Override - public EventSubscription subscribe(@NonNull Extension extension, @NonNull Class eventClass, @NonNull Consumer consumer) { - return this.eventBus.subscribe(extension, eventClass, consumer); - } - - @Override - public void unsubscribe(@NonNull EventSubscription subscription) { - this.eventBus.unsubscribe(subscription); - } - - @Override - public void register(@NonNull Extension extension, @NonNull Object eventHolder) { - this.eventBus.register(extension, eventHolder); - } - - @Override - public void unregisterAll(@NonNull Extension extension) { - this.eventBus.unregisterAll(extension); + public void unsubscribe(@NonNull EventSubscriber subscription) { + eventBus.unsubscribe(subscription); } @Override public boolean fire(@NonNull Event event) { - return this.eventBus.fire(event); + return eventBus.fire(event); } - @NonNull @Override - public Set> subscriptions(@NonNull Class eventClass) { - return this.eventBus.subscriptions(eventClass); + public @NonNull Set> subscribers(@NonNull Class eventClass) { + return eventBus.subscribers(eventClass); + } + + @Override + public void register(@NonNull Object listener) { + eventBus.register(extension, listener); + } + + @Override + @SuppressWarnings("unchecked") + public > @NonNull U subscribe( + @NonNull Class eventClass, @NonNull Consumer consumer) { + return eventBus.subscribe(extension, eventClass, consumer); + } + + @Override + public void unregisterAll() { + eventBus.unregisterAll(extension); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 72ec4af1e..e6d1cb3e4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -52,6 +52,7 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomItemsEvent; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; +import org.geysermc.geyser.event.type.DefineCustomItemsEvent; import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.mappings.MappingsConfigReader; @@ -108,7 +109,7 @@ public class ItemRegistryPopulator { }); nonVanillaCustomItems = new ObjectArrayList<>(); - GeyserImpl.getInstance().eventBus().fire(new GeyserDefineCustomItemsEvent(customItems, nonVanillaCustomItems) { + GeyserImpl.getInstance().eventBus().fire(new DefineCustomItemsEvent(customItems, nonVanillaCustomItems) { @Override public boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData) { if (CustomItemRegistryPopulator.initialCheck(identifier, customItemData, items)) { 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 135/290] 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 136/290] 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 3716b7a84f71022538adea40bc778311bb7691fa Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 20 Aug 2022 14:56:40 -0400 Subject: [PATCH 137/290] Remove initialized check in movement This probably isn't needed anymore. This was introduced in https://github.com/GeyserMC/Geyser/pull/41 and is probably no longer needed since we never send movement before the player is spawned, and we don't allow movement to go through until the Bedrock player matches the unconfirmed teleport we create in JavaPlayerPositionTranslator. By removing this we should fix some instances of players kicked for 'flying' as players joining in the air would never respond to gravity until Bedrock finished loading. --- .../entity/player/BedrockMovePlayerTranslator.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index ba4652726..17d424b00 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java @@ -31,13 +31,12 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.github.steveice10.packetlib.packet.Packet; import com.nukkitx.math.vector.Vector3d; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -49,17 +48,6 @@ public class BedrockMovePlayerTranslator extends PacketTranslator Date: Sat, 20 Aug 2022 16:32:24 -0400 Subject: [PATCH 138/290] Geyser end of https://github.com/GeyserMC/GeyserOptionalPack/pull/34 --- .../java/org/geysermc/geyser/entity/type/LivingEntity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java index 2550643d3..f7e055417 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java @@ -106,6 +106,9 @@ public class LivingEntity extends Entity { // Riptide spin attack setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04); + + // OptionalPack usage + setFlag(EntityFlag.EMERGING, isUsingItem && isUsingOffhand); } public void setHealth(FloatEntityMetadata entityMetadata) { From 67a65c45d3f5530b31fa4ca587d339a77018d4c9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 21 Aug 2022 21:22:15 -0400 Subject: [PATCH 139/290] Implement update notifications for Geyser Geyser installations will now get notified when a new Bedrock release is out and Geyser must be updated. The system works similarly to ViaVersion where OPs get a notification of an update when they join. The permission node for players to see update notifications is `geyser.update` and the backing JSON that controls this can be found at https://github.com/GeyserMC/GeyserSite/blob/gh-pages/versions.json. There is also a config option to disable update checking. This update also fixes modern Paper installations not being able to see colored text logged from Geyser in the console. --- bootstrap/bungeecord/pom.xml | 6 + .../bungeecord/GeyserBungeePlugin.java | 2 + .../GeyserBungeeUpdateListener.java | 48 ++++++ .../command/BungeeCommandSender.java | 23 ++- bootstrap/pom.xml | 4 + bootstrap/spigot/pom.xml | 11 +- .../platform/spigot/GeyserPaperLogger.java | 59 +++++++ .../platform/spigot/GeyserSpigotPlugin.java | 23 ++- .../spigot/GeyserSpigotUpdateListener.java | 48 ++++++ .../platform/spigot/PaperAdventure.java | 154 ++++++++++++++++++ .../spigot/command/SpigotCommandSender.java | 13 ++ .../manager/GeyserSpigotWorldManager.java | 8 +- .../standalone/GeyserStandaloneLogger.java | 23 +-- .../velocity/GeyserVelocityPlugin.java | 2 + .../GeyserVelocityUpdateListener.java | 47 ++++++ .../command/VelocityCommandSender.java | 7 + .../java/org/geysermc/geyser/Constants.java | 3 + .../java/org/geysermc/geyser/GeyserImpl.java | 10 +- .../org/geysermc/geyser/GeyserLogger.java | 34 +++- .../geyser/command/CommandSender.java | 6 + .../configuration/GeyserConfiguration.java | 2 + .../GeyserJacksonConfiguration.java | 3 + .../geyser/session/cache/WorldCache.java | 2 + .../geyser/util/VersionCheckUtils.java | 47 ++++++ .../org/geysermc/geyser/util/WebUtils.java | 2 + core/src/main/resources/config.yml | 5 + 26 files changed, 558 insertions(+), 34 deletions(-) create mode 100644 bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java create mode 100644 bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 5a1e8e262..d71a20f42 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -24,6 +24,12 @@ a7c6ede provided + + net.kyori + adventure-text-serializer-bungeecord + ${adventure-platform.version} + compile + ${outputName}-BungeeCord diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 0883c5ff0..e8d44b02f 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -149,6 +149,8 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(geyser)); + + this.getProxy().getPluginManager().registerListener(this, new GeyserBungeeUpdateListener()); } @Override diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java new file mode 100644 index 000000000..bbde8771e --- /dev/null +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.bungeecord; + +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; +import org.geysermc.geyser.Constants; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSender; +import org.geysermc.geyser.util.VersionCheckUtils; + +public final class GeyserBungeeUpdateListener implements Listener { + + @EventHandler + public void onPlayerJoin(final PostLoginEvent event) { + if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { + final ProxiedPlayer player = event.getPlayer(); + if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSender(player)); + } + } + } +} diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java index 05df8ba97..dcf5bd689 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java @@ -25,11 +25,15 @@ package org.geysermc.geyser.platform.bungeecord.command; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.text.GeyserLocale; +import java.util.Locale; + public class BungeeCommandSender implements CommandSender { private final net.md_5.bungee.api.CommandSender handle; @@ -50,6 +54,18 @@ public class BungeeCommandSender implements CommandSender { handle.sendMessage(TextComponent.fromLegacyText(message)); } + private static final int PROTOCOL_HEX_COLOR = 713; // Added 20w17a + + @Override + public void sendMessage(Component message) { + if (handle instanceof ProxiedPlayer player && player.getPendingConnection().getVersion() >= PROTOCOL_HEX_COLOR) { + // Include hex colors + handle.sendMessage(BungeeComponentSerializer.get().serialize(message)); + return; + } + handle.sendMessage(BungeeComponentSerializer.legacy().serialize(message)); + } + @Override public boolean isConsole() { return !(handle instanceof ProxiedPlayer); @@ -58,8 +74,11 @@ public class BungeeCommandSender implements CommandSender { @Override public String getLocale() { if (handle instanceof ProxiedPlayer player) { - String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry(); - return GeyserLocale.formatLocale(locale); + Locale locale = player.getLocale(); + if (locale != null) { + // Locale can be null early on in the conneciton + return GeyserLocale.formatLocale(locale.getLanguage() + "_" + locale.getCountry()); + } } return GeyserLocale.getDefaultLocale(); } diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 371ed9bca..35ec15abe 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -11,6 +11,10 @@ bootstrap-parent pom + + 4.1.2 + + spigot-public diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 5142d2bc3..ad4b58fe2 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -59,7 +59,13 @@ me.lucko commodore - 1.13 + 2.2 + compile + + + net.kyori + adventure-text-serializer-bungeecord + ${adventure-platform.version} compile @@ -107,6 +113,9 @@ net.kyori org.geysermc.geyser.platform.spigot.shaded.kyori + + net.kyori.adventure.text.logger.slf4j.ComponentLogger + org.objectweb.asm diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java new file mode 100644 index 000000000..930f84cec --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.spigot; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.logger.slf4j.ComponentLogger; +import org.bukkit.plugin.Plugin; + +import java.util.logging.Logger; + +public final class GeyserPaperLogger extends GeyserSpigotLogger { + private final ComponentLogger componentLogger; + + public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) { + super(logger, debug); + componentLogger = plugin.getComponentLogger(); + } + + /** + * Since 1.18.2 this is required so legacy format symbols don't show up in the console for colors + */ + @Override + public void sendMessage(Component message) { + // Done like this so the native component object field isn't relocated + componentLogger.info("{}", PaperAdventure.toNativeComponent(message)); + } + + static boolean supported() { + try { + Plugin.class.getMethod("getComponentLogger"); + return true; + } catch (NoSuchMethodException e) { + return false; + } + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 21c54308d..a1d9245e8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -123,6 +123,22 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } + try { + Class.forName("net.md_5.bungee.chat.ComponentSerializer"); + } catch (ClassNotFoundException e) { + if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat + getLogger().severe("*********************************************"); + getLogger().severe(""); + getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName())); + getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); + getLogger().severe(""); + getLogger().severe("*********************************************"); + + Bukkit.getPluginManager().disablePlugin(this); + return; + } + } + // By default this should be localhost but may need to be changed in some circumstances if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { geyserConfig.setAutoconfiguredRemote(true); @@ -137,7 +153,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.getBedrock().setPort(Bukkit.getPort()); } - this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); + this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) + : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); // Remove this in like a year @@ -266,12 +283,16 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { GeyserLocale.getLocaleStringLog(command.getDescription()), command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); } + Bukkit.getPluginManager().addPermission(new Permission(Constants.UPDATE_PERMISSION, + "Whether update notifications can be seen", PermissionDefault.OP)); // Events cannot be unregistered - re-registering results in duplicate firings GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); + + Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigotUpdateListener(), this); } boolean brigadierSupported = CommodoreProvider.isSupported(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java new file mode 100644 index 000000000..02f5367b3 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.spigot; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.geysermc.geyser.Constants; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.platform.spigot.command.SpigotCommandSender; +import org.geysermc.geyser.util.VersionCheckUtils; + +public final class GeyserSpigotUpdateListener implements Listener { + + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent event) { + if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { + final Player player = event.getPlayer(); + if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSender(player)); + } + } + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java new file mode 100644 index 000000000..5dd16da33 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.spigot; + +import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; +import net.kyori.adventure.text.Component; +import org.bukkit.command.CommandSender; +import org.geysermc.geyser.GeyserImpl; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Utility class for converting our shaded Adventure into the Adventure bundled in Paper. + * + * Code mostly taken from https://github.com/KyoriPowered/adventure-platform/blob/94d5821f2e755170f42bd8a5fe1d5bf6f66d04ad/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/PaperFacet.java#L46 + * and the MinecraftReflection class. + */ +public final class PaperAdventure { + private static final MethodHandle NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND; + private static final Method SEND_MESSAGE_COMPONENT; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + + MethodHandle nativeGsonComponentSerializerDeserializeMethodBound = null; + + // String.join because otherwise the class name will be relocated + final Class nativeGsonComponentSerializerClass = findClass(String.join(".", + "net", "kyori", "adventure", "text", "serializer", "gson", "GsonComponentSerializer")); + final Class nativeGsonComponentSerializerImplClass = findClass(String.join(".", + "net", "kyori", "adventure", "text", "serializer", "gson", "GsonComponentSerializerImpl")); + if (nativeGsonComponentSerializerClass != null && nativeGsonComponentSerializerImplClass != null) { + MethodHandle nativeGsonComponentSerializerGsonGetter = null; + try { + nativeGsonComponentSerializerGsonGetter = lookup.findStatic(nativeGsonComponentSerializerClass, + "gson", MethodType.methodType(nativeGsonComponentSerializerClass)); + } catch (final NoSuchMethodException | IllegalAccessException ignored) { + } + + MethodHandle nativeGsonComponentSerializerDeserializeMethod = null; + try { + final Method method = nativeGsonComponentSerializerImplClass.getDeclaredMethod("deserialize", String.class); + method.setAccessible(true); + nativeGsonComponentSerializerDeserializeMethod = lookup.unreflect(method); + } catch (final NoSuchMethodException | IllegalAccessException ignored) { + } + + if (nativeGsonComponentSerializerGsonGetter != null) { + if (nativeGsonComponentSerializerDeserializeMethod != null) { + try { + nativeGsonComponentSerializerDeserializeMethodBound = nativeGsonComponentSerializerDeserializeMethod + .bindTo(nativeGsonComponentSerializerGsonGetter.invoke()); + } catch (final Throwable throwable) { + GeyserImpl.getInstance().getLogger().error("Failed to access native GsonComponentSerializer", throwable); + } + } + } + } + + NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND = nativeGsonComponentSerializerDeserializeMethodBound; + + Method playerComponentSendMessage = null; + final Class nativeComponentClass = findClass(String.join(".", + "net", "kyori", "adventure", "text", "Component")); + if (nativeComponentClass != null) { + try { + playerComponentSendMessage = CommandSender.class.getMethod("sendMessage", nativeComponentClass); + } catch (final NoSuchMethodException e) { + if (GeyserImpl.getInstance().getLogger().isDebug()) { + e.printStackTrace(); + } + } + } + SEND_MESSAGE_COMPONENT = playerComponentSendMessage; + } + + public static Object toNativeComponent(final Component component) { + if (NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND == null) { + GeyserImpl.getInstance().getLogger().error("Illegal state where Component serialization was called when it wasn't available!"); + return null; + } + + try { + return NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND.invoke(DefaultComponentSerializer.get().serialize(component)); + } catch (final Throwable throwable) { + GeyserImpl.getInstance().getLogger().error("Failed to create native Component message", throwable); + return null; + } + } + + public static void sendMessage(final CommandSender sender, final Component component) { + if (SEND_MESSAGE_COMPONENT == null) { + GeyserImpl.getInstance().getLogger().error("Illegal state where Component sendMessage was called when it wasn't available!"); + return; + } + + final Object nativeComponent = toNativeComponent(component); + if (nativeComponent != null) { + try { + SEND_MESSAGE_COMPONENT.invoke(sender, nativeComponent); + } catch (final InvocationTargetException | IllegalAccessException e) { + GeyserImpl.getInstance().getLogger().error("Failed to send native Component message", e); + } + } + } + + public static boolean canSendMessageUsingComponent() { + return SEND_MESSAGE_COMPONENT != null; + } + + /** + * Gets a class by the first name available. + * + * @return a class or {@code null} if not found + */ + private static @Nullable Class findClass(final String className) { + try { + return Class.forName(className); + } catch (final ClassNotFoundException ignored) { + } + return null; + } + + private PaperAdventure() { + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java index a05a6ebe0..c6314ced5 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java @@ -25,10 +25,13 @@ package org.geysermc.geyser.platform.spigot.command; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.platform.spigot.PaperAdventure; import org.geysermc.geyser.text.GeyserLocale; import java.lang.reflect.InvocationTargetException; @@ -63,6 +66,16 @@ public class SpigotCommandSender implements CommandSender { handle.sendMessage(message); } + @Override + public void sendMessage(Component message) { + if (PaperAdventure.canSendMessageUsingComponent()) { + PaperAdventure.sendMessage(handle, message); + return; + } + + handle.sendMessage(BungeeComponentSerializer.get().serialize(message)); + } + @Override public boolean isConsole() { return handle instanceof ConsoleCommandSender; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index a03549444..0a6117b43 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -38,14 +38,14 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import org.bukkit.plugin.Plugin; -import org.geysermc.geyser.network.MinecraftProtocol; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; +import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.util.BlockEntityUtils; -import org.geysermc.geyser.level.GameRule; import java.util.ArrayList; import java.util.List; diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java index 3bd2a3960..78e603d7c 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java @@ -31,11 +31,10 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.text.ChatColor; @Log4j2 -public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, CommandSender { +public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger { @Override protected boolean isRunning() { @@ -95,24 +94,4 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey public boolean isDebug() { return log.isDebugEnabled(); } - - @Override - public String name() { - return "CONSOLE"; - } - - @Override - public void sendMessage(String message) { - info(message); - } - - @Override - public boolean isConsole() { - return true; - } - - @Override - public boolean hasPermission(String permission) { - return true; - } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 4a8a50da8..13a07121e 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -161,6 +161,8 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { } else { this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer); } + + proxyServer.getEventManager().register(this, new GeyserVelocityUpdateListener()); } @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java new file mode 100644 index 000000000..506dfff71 --- /dev/null +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.velocity; + +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.PostLoginEvent; +import com.velocitypowered.api.proxy.Player; +import org.geysermc.geyser.Constants; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.platform.velocity.command.VelocityCommandSender; +import org.geysermc.geyser.util.VersionCheckUtils; + +public final class GeyserVelocityUpdateListener { + + @Subscribe + public void onPlayerJoin(PostLoginEvent event) { + if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { + final Player player = event.getPlayer(); + if (player.hasPermission(Constants.UPDATE_PERMISSION)) { + VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSender(player)); + } + } + } +} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java index d5e4804ee..a5474c3e0 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.platform.velocity.command; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.Player; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.text.GeyserLocale; @@ -59,6 +60,12 @@ public class VelocityCommandSender implements CommandSender { handle.sendMessage(LegacyComponentSerializer.legacy('§').deserialize(message)); } + @Override + public void sendMessage(Component message) { + // Be careful that we don't shade in Adventure!! + handle.sendMessage(message); + } + @Override public boolean isConsole() { return handle instanceof ConsoleCommandSource; diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 23fb76d16..6a53c37de 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -37,6 +37,9 @@ public final class Constants { public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"; + public static final String GEYSER_DOWNLOAD_LOCATION = "https://ci.geysermc.org"; + public static final String UPDATE_PERMISSION = "geyser.update"; + static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; static { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 4322dde59..d9f4d8a15 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -41,6 +41,8 @@ import io.netty.util.internal.SystemPropertyUtil; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; @@ -66,7 +68,6 @@ import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.SkinProvider; -import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; @@ -303,8 +304,8 @@ public class GeyserImpl implements GeyserApi { int port = config.getBedrock().getPort(); logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); if (!"0.0.0.0".equals(address)) { - logger.info(ChatColor.GREEN + "Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0"); - logger.info(ChatColor.GREEN + "Then, restart this server."); + logger.info(Component.text("Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0", NamedTextColor.GREEN)); + logger.info(Component.text("Then, restart this server.", NamedTextColor.GREEN)); } } }).join(); @@ -454,6 +455,9 @@ public class GeyserImpl implements GeyserApi { } newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED); + if (config.isNotifyOnNewBedrockUpdate()) { + VersionCheckUtils.checkForGeyserUpdate(this::getLogger); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java index b47801cb5..197a031dd 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java @@ -25,9 +25,12 @@ package org.geysermc.geyser; +import net.kyori.adventure.text.Component; +import org.geysermc.geyser.command.CommandSender; + import javax.annotation.Nullable; -public interface GeyserLogger { +public interface GeyserLogger extends CommandSender { /** * Logs a severe message to console @@ -73,6 +76,15 @@ public interface GeyserLogger { */ void info(String message); + /** + * Logs an info component to console + * + * @param message the message to log + */ + default void info(Component message) { + sendMessage(message); + } + /** * Logs a debug message to console * @@ -100,4 +112,24 @@ public interface GeyserLogger { * If debug is enabled for this logger */ boolean isDebug(); + + @Override + default String name() { + return "CONSOLE"; + } + + @Override + default void sendMessage(String message) { + info(message); + } + + @Override + default boolean isConsole() { + return true; + } + + @Override + default boolean hasPermission(String permission) { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java b/core/src/main/java/org/geysermc/geyser/command/CommandSender.java index d9d1bcfbc..61adad717 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandSender.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.command; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.geyser.text.GeyserLocale; /** @@ -43,6 +45,10 @@ public interface CommandSender { void sendMessage(String message); + default void sendMessage(Component message) { + sendMessage(LegacyComponentSerializer.legacySection().serialize(message)); + } + /** * @return true if the specified sender is from the console. */ diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index 1f188cf40..f605ad103 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -105,6 +105,8 @@ public interface GeyserConfiguration { int getCustomSkullRenderDistance(); + boolean isNotifyOnNewBedrockUpdate(); + IMetricsInfo getMetrics(); int getPendingAuthenticationTimeout(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 30a947e53..80fa22ede 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -148,6 +148,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("xbox-achievements-enabled") private boolean xboxAchievementsEnabled = false; + @JsonProperty("notify-on-new-bedrock-update") + private boolean notifyOnNewBedrockUpdate = true; + private MetricsInfo metrics = new MetricsInfo(); @JsonProperty("pending-authentication-timeout") diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index 239f5c865..7996d1188 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; +import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; import org.geysermc.geyser.session.GeyserSession; @@ -172,6 +173,7 @@ public final class WorldCache { if (serverVerifiedState.sequence <= sequence) { // This block may be out of sync with the server // In 1.19.0 Java, you can verify this by trying to mine in spawn protection + System.out.println("Resetting " + entry.getKey() + " to " + BlockRegistries.JAVA_BLOCKS.get(serverVerifiedState.blockState).getJavaIdentifier()); ChunkUtils.updateBlockClientSide(session, serverVerifiedState.blockState, entry.getKey()); it.remove(); } diff --git a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java index 934680ce1..b1f97989f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java @@ -25,10 +25,22 @@ package org.geysermc.geyser.util; +import com.fasterxml.jackson.databind.JsonNode; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.geysermc.geyser.Constants; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.text.GeyserLocale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + public final class VersionCheckUtils { public static void checkForOutdatedFloodgate(GeyserLogger logger) { @@ -42,6 +54,41 @@ public final class VersionCheckUtils { } } + public static void checkForGeyserUpdate(Supplier recipient) { + CompletableFuture.runAsync(() -> { + try { + JsonNode json = WebUtils.getJson("https://api.geysermc.org/v2/versions/geyser"); + JsonNode bedrock = json.get("bedrock").get("protocol"); + int protocolVersion = bedrock.get("id").asInt(); + if (MinecraftProtocol.getBedrockCodec(protocolVersion) != null) { + // We support the latest version! No need to print a message. + return; + } + + final String newBedrockVersion = bedrock.get("name").asText(); + + // Delayed for two reasons: save unnecessary processing, and wait to load locale if this is on join. + CommandSender sender = recipient.get(); + + // Overarching component is green - geyser.version.new component cannot be green or else the link blue is overshadowed + Component message = Component.text().color(NamedTextColor.GREEN) + .append(Component.text(GeyserLocale.getPlayerLocaleString("geyser.version.new", sender.getLocale(), newBedrockVersion)) + .replaceText(TextReplacementConfig.builder() + .match("\\{1\\}") // Replace "Download here: {1}" so we can use fancy text component yesyes + .replacement(Component.text() + .content(Constants.GEYSER_DOWNLOAD_LOCATION) + .color(NamedTextColor.BLUE) + .decoration(TextDecoration.UNDERLINED, TextDecoration.State.TRUE) + .clickEvent(ClickEvent.openUrl(Constants.GEYSER_DOWNLOAD_LOCATION))) + .build())) + .build(); + sender.sendMessage(message); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error whilst checking for Geyser update!", e); + } + }); + } + private VersionCheckUtils() { } } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index f9574f08b..c0889f1c5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -73,6 +73,8 @@ public class WebUtils { public static JsonNode getJson(String reqURL) throws IOException { HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setConnectTimeout(10000); + con.setReadTimeout(10000); return GeyserImpl.JSON_MAPPER.readTree(con.getInputStream()); } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index c331a7e62..5a32a6599 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -175,6 +175,11 @@ force-resource-packs: true # THIS DISABLES ALL COMMANDS FROM SUCCESSFULLY RUNNING FOR BEDROCK IN-GAME, as otherwise Bedrock thinks you are cheating. xbox-achievements-enabled: false +# Whether to alert the console and operators that a new Geyser version is available that supports a Bedrock version +# that this Geyser version does not support. It's recommended to keep this option enabled, as many Bedrock platforms +# auto-update. +notify-on-new-bedrock-update: true + # bStats is a stat tracker that is entirely anonymous and tracks only basic information # about Geyser, such as how many people are online, how many servers are using Geyser, # what OS is being used, etc. You can learn more about bStats here: https://bstats.org/. From d499e22502208fcc974f82233f9ef24e92de6f90 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 21 Aug 2022 21:25:32 -0400 Subject: [PATCH 140/290] Debugging always sneaks in... --- .../main/java/org/geysermc/geyser/session/cache/WorldCache.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index 7996d1188..30f8c3ba8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -173,7 +173,6 @@ public final class WorldCache { if (serverVerifiedState.sequence <= sequence) { // This block may be out of sync with the server // In 1.19.0 Java, you can verify this by trying to mine in spawn protection - System.out.println("Resetting " + entry.getKey() + " to " + BlockRegistries.JAVA_BLOCKS.get(serverVerifiedState.blockState).getJavaIdentifier()); ChunkUtils.updateBlockClientSide(session, serverVerifiedState.blockState, entry.getKey()); it.remove(); } From 82411978c859205e78b1c8c4da7c1c7b7999eb2a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 22 Aug 2022 14:34:26 -0400 Subject: [PATCH 141/290] Update languages submodule --- core/src/main/resources/languages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 4351fc11d..ad92d550b 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 4351fc11d5fbd9fecc8334910234cdf8a4bc730b +Subproject commit ad92d550bab49bc46f17db6aa0042035b66a1a10 From 8dde4b434790e40221cf147e47e4aa83e3263893 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 23 Aug 2022 13:20:57 -0400 Subject: [PATCH 142/290] Support Bedrock 1.19.21 --- .../java/org/geysermc/geyser/network/MinecraftProtocol.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 3452ec7d5..98f431d15 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -45,7 +45,10 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v544.V544_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v544.V544_CODEC.toBuilder() + .minecraftVersion("1.19.21") + .protocolVersion(545) + .build(); /** * A list of all supported Bedrock versions that can join Geyser */ @@ -64,6 +67,7 @@ public final class MinecraftProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v534.V534_CODEC.toBuilder() .minecraftVersion("1.19.10/1.19.11") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } From e35f3785b2566b3f8ca78ff7fea271afe71ac8c2 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Aug 2022 04:53:13 +0000 Subject: [PATCH 143/290] Resolve fallout --- api/geyser/build.gradle.kts | 2 ++ bootstrap/bungeecord/build.gradle.kts | 2 ++ .../bungeecord/GeyserBungeeUpdateListener.java | 4 ++-- bootstrap/spigot/build.gradle.kts | 7 ++++++- .../platform/spigot/GeyserSpigotUpdateListener.java | 4 ++-- .../velocity/GeyserVelocityUpdateListener.java | 4 ++-- build-logic/src/main/kotlin/Versions.kt | 1 + .../main/java/org/geysermc/geyser/GeyserLogger.java | 4 ++-- .../BedrockInventoryTransactionTranslator.java | 4 ++-- .../org/geysermc/geyser/util/VersionCheckUtils.java | 12 ++++++------ 10 files changed, 27 insertions(+), 17 deletions(-) diff --git a/api/geyser/build.gradle.kts b/api/geyser/build.gradle.kts index dcde85337..60bd4a431 100644 --- a/api/geyser/build.gradle.kts +++ b/api/geyser/build.gradle.kts @@ -4,6 +4,8 @@ plugins { dependencies { api(projects.api) + + implementation("net.kyori", "adventure-text-serializer-legacy", Versions.adventureVersion) } publishing { diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 873df692a..9f3b49b67 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -2,6 +2,8 @@ val bungeeVersion = "a7c6ede"; dependencies { api(projects.core) + + implementation("net.kyori", "adventure-text-serializer-bungeecord", Versions.adventurePlatformVersion) } platformRelocate("net.md_5.bungee.jni") diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java index bbde8771e..c68839b20 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeUpdateListener.java @@ -31,7 +31,7 @@ import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSender; +import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; public final class GeyserBungeeUpdateListener implements Listener { @@ -41,7 +41,7 @@ public final class GeyserBungeeUpdateListener implements Listener { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final ProxiedPlayer player = event.getPlayer(); if (player.hasPermission(Constants.UPDATE_PERMISSION)) { - VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSender(player)); + VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player)); } } } diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 02883999d..2fe3d6e2b 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -1,7 +1,7 @@ val paperVersion = "1.19-R0.1-SNAPSHOT" val viaVersion = "4.0.0" val adaptersVersion = "1.5-SNAPSHOT" -val commodoreVersion = "1.13" +val commodoreVersion = "2.2" dependencies { api(projects.core) @@ -9,6 +9,8 @@ dependencies { implementation("org.geysermc.geyser.adapters", "spigot-all", adaptersVersion) implementation("me.lucko", "commodore", commodoreVersion) + + implementation("net.kyori", "adventure-text-serializer-bungeecord", Versions.adventurePlatformVersion) // Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19 compileOnly("io.papermc.paper", "paper-api", paperVersion) { @@ -61,5 +63,8 @@ tasks.withType { // Commodore includes Brigadier exclude(dependency("com.mojang:.*")) + + // Adventure slf4j + exclude(dependency("net.kyori.adventure.text.logger.slf4j:ComponentLogger")) } } \ No newline at end of file diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java index 02f5367b3..5e3c4def8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotUpdateListener.java @@ -31,7 +31,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.platform.spigot.command.SpigotCommandSender; +import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; public final class GeyserSpigotUpdateListener implements Listener { @@ -41,7 +41,7 @@ public final class GeyserSpigotUpdateListener implements Listener { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final Player player = event.getPlayer(); if (player.hasPermission(Constants.UPDATE_PERMISSION)) { - VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSender(player)); + VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSource(player)); } } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java index 506dfff71..31e584612 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityUpdateListener.java @@ -30,7 +30,7 @@ import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.proxy.Player; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.platform.velocity.command.VelocityCommandSender; +import org.geysermc.geyser.platform.velocity.command.VelocityCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; public final class GeyserVelocityUpdateListener { @@ -40,7 +40,7 @@ public final class GeyserVelocityUpdateListener { if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) { final Player player = event.getPlayer(); if (player.hasPermission(Constants.UPDATE_PERMISSION)) { - VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSender(player)); + VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSource(player)); } } } diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index f7b20cca1..d4a0a80e3 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -39,6 +39,7 @@ object Versions { const val mcprotocollibversion = "9f78bd5" const val packetlibVersion = "3.0" const val adventureVersion = "4.9.3" + const val adventurePlatformVersion = "4.1.2" const val junitVersion = "4.13.1" const val checkerQualVersion = "3.19.0" const val cumulusVersion = "1.1.1" diff --git a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java index 197a031dd..88220eec9 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java @@ -26,11 +26,11 @@ package org.geysermc.geyser; import net.kyori.adventure.text.Component; -import org.geysermc.geyser.command.CommandSender; +import org.geysermc.geyser.command.GeyserCommandSource; import javax.annotation.Nullable; -public interface GeyserLogger extends CommandSender { +public interface GeyserLogger extends GeyserCommandSource { /** * Logs a severe message to console diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 02a7ddace..e72f7d786 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -54,7 +54,7 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -467,7 +467,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator recipient) { + public static void checkForGeyserUpdate(Supplier recipient) { CompletableFuture.runAsync(() -> { try { JsonNode json = WebUtils.getJson("https://api.geysermc.org/v2/versions/geyser"); JsonNode bedrock = json.get("bedrock").get("protocol"); int protocolVersion = bedrock.get("id").asInt(); - if (MinecraftProtocol.getBedrockCodec(protocolVersion) != null) { + if (GameProtocol.getBedrockCodec(protocolVersion) != null) { // We support the latest version! No need to print a message. return; } @@ -68,11 +68,11 @@ public final class VersionCheckUtils { final String newBedrockVersion = bedrock.get("name").asText(); // Delayed for two reasons: save unnecessary processing, and wait to load locale if this is on join. - CommandSender sender = recipient.get(); + GeyserCommandSource sender = recipient.get(); // Overarching component is green - geyser.version.new component cannot be green or else the link blue is overshadowed Component message = Component.text().color(NamedTextColor.GREEN) - .append(Component.text(GeyserLocale.getPlayerLocaleString("geyser.version.new", sender.getLocale(), newBedrockVersion)) + .append(Component.text(GeyserLocale.getPlayerLocaleString("geyser.version.new", sender.locale(), newBedrockVersion)) .replaceText(TextReplacementConfig.builder() .match("\\{1\\}") // Replace "Download here: {1}" so we can use fancy text component yesyes .replacement(Component.text() From dc29d997fd7e7ea81ca7bfe4534b6ea946ec24cd Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Aug 2022 05:18:12 +0000 Subject: [PATCH 144/290] Exclude from relocation, not inclusion --- bootstrap/spigot/build.gradle.kts | 4 ++-- build-logic/src/main/kotlin/extensions.kt | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 2fe3d6e2b..1b954e1d4 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { platformRelocate("it.unimi.dsi.fastutil") platformRelocate("com.fasterxml.jackson") -platformRelocate("net.kyori") +platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger") platformRelocate("org.objectweb.asm") platformRelocate("me.lucko.commodore") platformRelocate("io.netty.channel.kqueue") @@ -65,6 +65,6 @@ tasks.withType { exclude(dependency("com.mojang:.*")) // Adventure slf4j - exclude(dependency("net.kyori.adventure.text.logger.slf4j:ComponentLogger")) + //exclude(dependency("net.kyori.adventure.text.logger.slf4j:ComponentLogger")) } } \ No newline at end of file diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 1f9793ee4..43cdafdcc 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -43,9 +43,11 @@ fun Project.exclude(group: String) { } } -fun Project.platformRelocate(pattern: String) { +fun Project.platformRelocate(pattern: String, exclusion: String = "") { tasks.named("shadowJar") { - relocate(pattern, "org.geysermc.geyser.platform.${project.name}.shaded.$pattern") + relocate(pattern, "org.geysermc.geyser.platform.${project.name}.shaded.$pattern") { + exclude(exclusion) + } } } From f1642d81dc2e2c03ae9bb78c300c305aa6a9dbc3 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Aug 2022 13:41:24 +0000 Subject: [PATCH 145/290] Fix comment --- bootstrap/spigot/build.gradle.kts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 1b954e1d4..5a459a09b 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { platformRelocate("it.unimi.dsi.fastutil") platformRelocate("com.fasterxml.jackson") +// Relocate net.kyori but exclude the component logger platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger") platformRelocate("org.objectweb.asm") platformRelocate("me.lucko.commodore") @@ -63,8 +64,5 @@ tasks.withType { // Commodore includes Brigadier exclude(dependency("com.mojang:.*")) - - // Adventure slf4j - //exclude(dependency("net.kyori.adventure.text.logger.slf4j:ComponentLogger")) } } \ No newline at end of file From 936fed1ded9e8c778e296433a2221c693a9462ba Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Wed, 24 Aug 2022 15:38:54 +0000 Subject: [PATCH 146/290] Move sendMessage(Component) to GeyserCommandSource --- api/geyser/build.gradle.kts | 2 -- .../org/geysermc/geyser/api/command/CommandSource.java | 7 ------- .../org/geysermc/geyser/command/GeyserCommandSource.java | 6 ++++++ 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/geyser/build.gradle.kts b/api/geyser/build.gradle.kts index 60bd4a431..dcde85337 100644 --- a/api/geyser/build.gradle.kts +++ b/api/geyser/build.gradle.kts @@ -4,8 +4,6 @@ plugins { dependencies { api(projects.api) - - implementation("net.kyori", "adventure-text-serializer-legacy", Versions.adventureVersion) } publishing { diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java index 4465e79b2..aabf0c4e8 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java @@ -25,9 +25,6 @@ package org.geysermc.geyser.api.command; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; - /** * Represents an instance capable of sending commands. */ @@ -58,10 +55,6 @@ public interface CommandSource { } } - default void sendMessage(Component message) { - sendMessage(LegacyComponentSerializer.legacySection().serialize(message)); - } - /** * If this source is the console. * diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java index eabccc243..88d148b11 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandSource.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.command; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.text.GeyserLocale; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; /** * Implemented on top of any class that can send a command. @@ -40,4 +42,8 @@ public interface GeyserCommandSource extends CommandSource { default String locale() { return GeyserLocale.getDefaultLocale(); } + + default void sendMessage(Component message) { + sendMessage(LegacyComponentSerializer.legacySection().serialize(message)); + } } From 6ec1ba39c6ed5f452b141ad0b35ddea31f6ffc7a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Aug 2022 13:21:45 -0400 Subject: [PATCH 147/290] Add 1.19.21 to the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42979bdbe..fd253db77 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20/1.19.21 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From 29fcce7ec842ea92bd306e1a6d6603c7f8dfe748 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Aug 2022 16:10:43 -0400 Subject: [PATCH 148/290] Add option to not log player IP addresses Resolves #3246 --- .../geysermc/geyser/configuration/GeyserConfiguration.java | 2 ++ .../geyser/configuration/GeyserJacksonConfiguration.java | 3 +++ .../geyser/network/ConnectorServerEventHandler.java | 6 ++++-- .../java/org/geysermc/geyser/session/GeyserSession.java | 3 +-- core/src/main/resources/config.yml | 3 +++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index f605ad103..4d9b3f2a4 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -105,6 +105,8 @@ public interface GeyserConfiguration { int getCustomSkullRenderDistance(); + boolean isLogPlayerIpAddresses(); + boolean isNotifyOnNewBedrockUpdate(); IMetricsInfo getMetrics(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 80fa22ede..b93b9a6a0 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -148,6 +148,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("xbox-achievements-enabled") private boolean xboxAchievementsEnabled = false; + @JsonProperty("log-player-ip-addresses") + private boolean logPlayerIpAddresses = true; + @JsonProperty("notify-on-new-bedrock-update") private boolean notifyOnNewBedrockUpdate = true; diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index d41871cdb..1c6f9db88 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -84,14 +84,16 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { } } - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", inetSocketAddress)); + String ip = geyser.getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); return true; } @Override public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { if (geyser.getConfig().isDebugMode() && PRINT_DEBUG_PINGS) { - geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.pinged", inetSocketAddress)); + String ip = geyser.getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; + geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.pinged", ip)); } GeyserConfiguration config = geyser.getConfig(); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index f7c990ac3..4e00294a8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -135,7 +135,6 @@ import org.geysermc.geyser.util.MathUtils; import javax.annotation.Nonnull; import java.net.ConnectException; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -1045,7 +1044,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { } else { // Downstream's disconnect will fire an event that prints a log message // Otherwise, we print a message here - InetAddress address = upstream.getAddress().getAddress(); + String address = geyser.getConfig().isLogPlayerIpAddresses() ? upstream.getAddress().getAddress().toString() : ""; geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, reason)); } if (!upstream.isClosed()) { diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 5a32a6599..d5b9c755f 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -175,6 +175,9 @@ force-resource-packs: true # THIS DISABLES ALL COMMANDS FROM SUCCESSFULLY RUNNING FOR BEDROCK IN-GAME, as otherwise Bedrock thinks you are cheating. xbox-achievements-enabled: false +# Whether player IP addresses will be logged by the server. +log-player-ip-addresses: true + # Whether to alert the console and operators that a new Geyser version is available that supports a Bedrock version # that this Geyser version does not support. It's recommended to keep this option enabled, as many Bedrock platforms # auto-update. From b7337fa03268efb583dbfc4b7c7e39a713e57959 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 25 Aug 2022 16:11:30 -0400 Subject: [PATCH 149/290] Update mappings Fixes #3252 --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 2c68dab9d..f1c9c2fbb 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 2c68dab9d751f78b2f5b0298da5e338ad6bc07ca +Subproject commit f1c9c2fbba0e102dc4f8c96dd9485f7ec9768174 From 670308edc2a8dba8e34312481bb04036892477d7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 26 Aug 2022 11:19:23 -0400 Subject: [PATCH 150/290] Update Netty version used in standalone --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 489f99cb3..ca6d4d370 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -14,7 +14,7 @@ 4.12.0-20220629.025215-9 8.5.2 2.13.2 - 4.1.66.Final + 4.1.80.Final From 1db77ad2bd22d941750908a02bde1441838e29f0 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 28 Aug 2022 17:42:31 -0700 Subject: [PATCH 151/290] Fix address, port, & motd being ignored in config (#3259) --- .../geyser/configuration/GeyserJacksonConfiguration.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 9f2eaa898..acb78a8a3 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -159,6 +159,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonIgnoreProperties(ignoreUnknown = true) public static class BedrockConfiguration implements IBedrockConfiguration { @AsteriskSerializer.Asterisk(isIp = true) + @JsonProperty("address") private String address = "0.0.0.0"; @Override @@ -167,6 +168,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration } @Setter + @JsonProperty("port") private int port = 19132; @Override @@ -178,6 +180,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("clone-remote-port") private boolean cloneRemotePort = false; + @JsonProperty("motd1") private String motd1 = "GeyserMC"; @Override @@ -185,6 +188,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration return motd1; } + @JsonProperty("motd2") private String motd2 = "Geyser"; @Override @@ -237,6 +241,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration public static class RemoteConfiguration implements IRemoteConfiguration { @Setter @AsteriskSerializer.Asterisk(isIp = true) + @JsonProperty("address") private String address = "auto"; @Override @@ -246,6 +251,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonDeserialize(using = PortDeserializer.class) @Setter + @JsonProperty("port") private int port = 25565; @Override From 8e47a9f5e9b27819dedcd403b143f4cf0e7ec0dc Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 29 Aug 2022 12:26:30 -0400 Subject: [PATCH 152/290] Ensure bedrock inventory id is at most 100 (#3260) --- .../org/geysermc/geyser/inventory/Inventory.java | 13 ++++++++++--- .../geysermc/geyser/inventory/click/ClickPlan.java | 2 +- .../inventory/holder/BlockInventoryHolder.java | 4 ++-- .../inventory/updater/ChestInventoryUpdater.java | 4 ++-- .../updater/ContainerInventoryUpdater.java | 4 ++-- .../inventory/updater/HorseInventoryUpdater.java | 2 +- .../inventory/BeaconInventoryTranslator.java | 2 +- .../inventory/BrewingInventoryTranslator.java | 4 ++-- .../inventory/EnchantingInventoryTranslator.java | 2 +- .../inventory/Generic3X3InventoryTranslator.java | 2 +- .../translator/inventory/InventoryTranslator.java | 2 +- .../inventory/LecternInventoryTranslator.java | 8 ++++---- .../inventory/LoomInventoryTranslator.java | 2 +- .../inventory/StonecutterInventoryTranslator.java | 2 +- .../chest/DoubleChestInventoryTranslator.java | 4 ++-- .../furnace/AbstractFurnaceInventoryTranslator.java | 2 +- .../horse/ChestedHorseInventoryTranslator.java | 2 +- .../bedrock/BedrockContainerCloseTranslator.java | 12 ++++++------ .../BedrockInventoryTransactionTranslator.java | 4 ++-- .../bedrock/BedrockLecternUpdateTranslator.java | 8 ++++---- .../inventory/JavaContainerCloseTranslator.java | 2 +- .../inventory/JavaMerchantOffersTranslator.java | 2 +- .../java/inventory/JavaOpenScreenTranslator.java | 4 ++-- .../org/geysermc/geyser/util/InventoryUtils.java | 12 ++++++------ 24 files changed, 56 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index ca7e90a25..137291dc9 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -45,7 +45,7 @@ import java.util.Arrays; @ToString public abstract class Inventory { @Getter - protected final int id; + protected final int javaId; /** * The Java inventory state ID from the server. As of Java Edition 1.18.1 this value has one instance per player. @@ -94,15 +94,22 @@ public abstract class Inventory { this("Inventory", id, size, containerType); } - protected Inventory(String title, int id, int size, ContainerType containerType) { + protected Inventory(String title, int javaId, int size, ContainerType containerType) { this.title = title; - this.id = id; + this.javaId = javaId; this.size = size; this.containerType = containerType; this.items = new GeyserItemStack[size]; Arrays.fill(items, GeyserItemStack.EMPTY); } + // This is to prevent conflicts with special bedrock inventory IDs. + // The vanilla java server only sends an ID between 1 and 100 when opening an inventory, + // so this is rarely needed. (certain plugins) + public int getBedrockId() { + return javaId <= 100 ? javaId : (javaId % 100) + 1; + } + public GeyserItemStack getItem(int slot) { if (slot > this.size) { GeyserImpl.getInstance().getLogger().debug("Tried to get an item out of bounds! " + this); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index ec36645da..da72f9f99 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -144,7 +144,7 @@ public final class ClickPlan { } ServerboundContainerClickPacket clickPacket = new ServerboundContainerClickPacket( - inventory.getId(), + inventory.getJavaId(), stateId, action.slot, action.click.actionType, diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index fd26cc170..379eb2566 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -133,7 +133,7 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) inventory.getId()); + containerOpenPacket.setId((byte) inventory.getBedrockId()); containerOpenPacket.setType(containerType); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); @@ -146,7 +146,7 @@ public class BlockInventoryHolder extends InventoryHolder { // No need to reset a block since we didn't change any blocks // But send a container close packet because we aren't destroying the original. ContainerClosePacket packet = new ContainerClosePacket(); - packet.setId((byte) inventory.getId()); + packet.setId((byte) inventory.getBedrockId()); packet.setUnknownBool0(true); //TODO needs to be changed in Protocol to "server-side" or something session.sendUpstreamPacket(packet); return; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java index 1e5c6946d..a468e53bc 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java @@ -59,7 +59,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { } InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); + contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(bedrockItems); session.sendUpstreamPacket(contentPacket); } @@ -70,7 +70,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { return true; InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); + slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java index 705a8b242..c943a62b4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java @@ -47,7 +47,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { } InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); + contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); session.sendUpstreamPacket(contentPacket); } @@ -58,7 +58,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { return true; InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); + slotPacket.setContainerId(inventory.getBedrockId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session)); session.sendUpstreamPacket(slotPacket); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java index fa680c201..20ce7e467 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java @@ -47,7 +47,7 @@ public class HorseInventoryUpdater extends InventoryUpdater { } InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); + contentPacket.setContainerId(inventory.getBedrockId()); contentPacket.setContents(Arrays.asList(bedrockItems)); session.sendUpstreamPacket(contentPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index 4dac5e86f..304b8ef00 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -62,7 +62,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator @Override public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { if (!((BeaconContainer) inventory).isUsingRealBlock()) { - InventoryUtils.closeInventory(session, inventory.getId(), false); + InventoryUtils.closeInventory(session, inventory.getJavaId(), false); return; } super.openInventory(translator, session, inventory); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java index 0c4fe12e7..b12cd8354 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java @@ -43,7 +43,7 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator public void openInventory(GeyserSession session, Inventory inventory) { super.openInventory(session, inventory); ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); + dataPacket.setWindowId((byte) inventory.getBedrockId()); dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL); dataPacket.setValue(20); session.sendUpstreamPacket(dataPacket); @@ -52,7 +52,7 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); + dataPacket.setWindowId((byte) inventory.getBedrockId()); switch (key) { case 0: dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index 800b35901..97946b59c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -127,7 +127,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla // Slot should be determined as 0, 1, or 2 return rejectRequest(request); } - ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), javaSlot); + ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), javaSlot); session.sendDownstreamPacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index 23bab8c0e..9f7a52107 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -52,7 +52,7 @@ public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTransla @Override public void openInventory(GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) inventory.getId()); + containerOpenPacket.setId((byte) inventory.getBedrockId()); // Required for opening the real block - otherwise, if the container type is incorrect, it refuses to open containerOpenPacket.setType(((Generic3X3Container) inventory).isDropper() ? com.nukkitx.protocol.bedrock.data.inventory.ContainerType.DROPPER : com.nukkitx.protocol.bedrock.data.inventory.ContainerType.DISPENSER); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index 6f4ca7ee4..394a394ed 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -804,7 +804,7 @@ public abstract class InventoryTranslator { */ //TODO: compatibility for simulated inventory (ClickPlan) private static int findTempSlot(Inventory inventory, GeyserItemStack item, boolean emptyOnly, int... slotBlacklist) { - int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable temp slot + int offset = inventory.getJavaId() == 0 ? 1 : 0; //offhand is not a viable temp slot HashSet itemBlacklist = new HashSet<>(slotBlacklist.length + 1); itemBlacklist.add(item); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index fc4090c73..f6d24363a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -99,10 +99,10 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { LecternContainer lecternContainer = (LecternContainer) inventory; if (session.isDroppingLecternBook()) { // We have to enter the inventory GUI to eject the book - ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), 3); + ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3); session.sendDownstreamPacket(packet); session.setDroppingLecternBook(false); - InventoryUtils.closeInventory(session, inventory.getId(), false); + InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } else if (lecternContainer.getBlockEntityTag() == null) { CompoundTag tag = book.getNbt(); // Position has to be the last interacted position... right? @@ -150,9 +150,9 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position); session.getLecternCache().add(position); // Close the window - we will reopen it once the client has this data synced - ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getId()); + ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); session.sendDownstreamPacket(closeWindowPacket); - InventoryUtils.closeInventory(session, inventory.getId(), false); + InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 5a237b72a..d44ff589a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -147,7 +147,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { // Java's formula: 4 * row + col // And the Java loom window has a fixed row/width of four // So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :) - ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), index); + ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), index); session.sendDownstreamPacket(packet); GeyserItemStack inputCopy = inventory.getItem(0).copy(1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index e0e2e27bd..1668e3a93 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -68,7 +68,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl ItemStack javaOutput = craftingData.output(); // Getting the index of the item in the Java stonecutter list - ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), button); + ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), button); session.sendDownstreamPacket(packet); container.setStonecutterButton(button); if (inventory.getItem(1).getJavaId() != javaOutput.getId()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index fc3279de1..ec5c882c3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -130,7 +130,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void openInventory(GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) inventory.getId()); + containerOpenPacket.setId((byte) inventory.getBedrockId()); containerOpenPacket.setType(ContainerType.CONTAINER); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); @@ -143,7 +143,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { // No need to reset a block since we didn't change any blocks // But send a container close packet because we aren't destroying the original. ContainerClosePacket packet = new ContainerClosePacket(); - packet.setId((byte) inventory.getId()); + packet.setId((byte) inventory.getBedrockId()); packet.setUnknownBool0(true); //TODO needs to be changed in Protocol to "server-side" or something session.sendUpstreamPacket(packet); return; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java index 472f92b4d..6794b17e4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java @@ -43,7 +43,7 @@ public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockIn @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { ContainerSetDataPacket dataPacket = new ContainerSetDataPacket(); - dataPacket.setWindowId((byte) inventory.getId()); + dataPacket.setWindowId((byte) inventory.getBedrockId()); switch (key) { case 0: dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index 035f8efa2..08462249e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -105,7 +105,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven } InventoryContentPacket horseContentsPacket = new InventoryContentPacket(); - horseContentsPacket.setContainerId(inventory.getId()); + horseContentsPacket.setContainerId(inventory.getBedrockId()); horseContentsPacket.setContents(Arrays.asList(horseItems)); session.sendUpstreamPacket(horseContentsPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java index a3f4b4959..9a1979c23 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java @@ -40,23 +40,23 @@ public class BedrockContainerCloseTranslator extends PacketTranslator currentJavaPage) { for (int i = currentJavaPage; i < newJavaPage; i++) { - ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getId(), 2); + ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2); session.sendDownstreamPacket(clickButtonPacket); } } else { for (int i = currentJavaPage; i > newJavaPage; i--) { - ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getId(), 1); + ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1); session.sendDownstreamPacket(clickButtonPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java index 934ee882d..9f687f046 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerCloseTranslator.java @@ -38,6 +38,6 @@ public class JavaContainerCloseTranslator extends PacketTranslator { Inventory openInv = session.getOpenInventory(); - if (openInv != null && openInv.getId() == inventory.getId()) { + if (openInv != null && openInv.getJavaId() == inventory.getJavaId()) { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); } else if (openInv != null && openInv.isPending()) { @@ -108,11 +108,11 @@ public class InventoryUtils { } } - public static void closeInventory(GeyserSession session, int windowId, boolean confirm) { + public static void closeInventory(GeyserSession session, int javaId, boolean confirm) { session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session); updateCursor(session); - Inventory inventory = getInventory(session, windowId); + Inventory inventory = getInventory(session, javaId); if (inventory != null) { InventoryTranslator translator = session.getInventoryTranslator(); translator.closeInventory(session, inventory); @@ -124,12 +124,12 @@ public class InventoryUtils { session.setOpenInventory(null); } - public static Inventory getInventory(GeyserSession session, int windowId) { - if (windowId == 0) { + public static Inventory getInventory(GeyserSession session, int javaId) { + if (javaId == 0) { return session.getPlayerInventory(); } else { Inventory openInventory = session.getOpenInventory(); - if (openInventory != null && windowId == openInventory.getId()) { + if (openInventory != null && javaId == openInventory.getJavaId()) { return openInventory; } return null; From 94d56f04bb2f92ffb9a999a7429bbcc5d96c51a5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 29 Aug 2022 12:29:45 -0400 Subject: [PATCH 153/290] Spigot: Use most compatible signature for CommandSender#sendMessage --- .../geyser/platform/spigot/command/SpigotCommandSender.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java index c6314ced5..cef92f744 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java @@ -73,7 +73,8 @@ public class SpigotCommandSender implements CommandSender { return; } - handle.sendMessage(BungeeComponentSerializer.get().serialize(message)); + // CommandSender#sendMessage(BaseComponent[]) is Paper-only + handle.spigot().sendMessage(BungeeComponentSerializer.get().serialize(message)); } @Override From d9db035d95309e42ef17571fbc78aead51d1882d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 29 Aug 2022 12:30:16 -0400 Subject: [PATCH 154/290] Add example issue to Inventory#getBedrockId --- core/src/main/java/org/geysermc/geyser/inventory/Inventory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 137291dc9..29233a2e7 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -106,6 +106,7 @@ public abstract class Inventory { // This is to prevent conflicts with special bedrock inventory IDs. // The vanilla java server only sends an ID between 1 and 100 when opening an inventory, // so this is rarely needed. (certain plugins) + // Example: https://github.com/GeyserMC/Geyser/issues/3254 public int getBedrockId() { return javaId <= 100 ? javaId : (javaId % 100) + 1; } From f8a84f977737d39412eb70cd4b523816e6e8ab0a Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Wed, 31 Aug 2022 16:42:38 -0400 Subject: [PATCH 155/290] Loopback exemption fixes (#3261) * Fix potential hang when checking loopback exemptions * Remove single quotes from LoopbackExempt command --- .../main/java/org/geysermc/geyser/util/LoopbackUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java b/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java index b543e4a48..bb92e6cd1 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoopbackUtil.java @@ -35,7 +35,7 @@ import java.nio.file.Paths; public final class LoopbackUtil { private static final String checkExemption = "CheckNetIsolation LoopbackExempt -s"; - private static final String loopbackCommand = "CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'"; + private static final String loopbackCommand = "CheckNetIsolation LoopbackExempt -a -n=Microsoft.MinecraftUWP_8wekyb3d8bbwe"; /** * This string needs to be checked in the event Minecraft is not installed - no Minecraft string will be present in the checkExemption command. */ @@ -50,12 +50,12 @@ public final class LoopbackUtil { if (os.equalsIgnoreCase("Windows 10") || os.equalsIgnoreCase("Windows 11")) { try { Process process = Runtime.getRuntime().exec(checkExemption); - process.waitFor(); InputStream is = process.getInputStream(); + int data; StringBuilder sb = new StringBuilder(); - while (is.available() != 0) { - sb.append((char) is.read()); + while ((data = is.read()) != -1) { + sb.append((char) data); } return !sb.toString().contains(minecraftApplication); From c07c7b933749630eb3512ea59ae0cbd659eb4f76 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 1 Sep 2022 00:50:03 +0200 Subject: [PATCH 156/290] Added support for latest events version --- .../geysermc/geyser/event/GeyserEventBus.java | 15 +++++++++++---- .../geyser/event/GeyserEventSubscriber.java | 18 ++++++++++++++---- .../event/GeyserExtensionEventBus.java | 15 +++++++++++---- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java index 7d0d6336d..f634931f4 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.event; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; +import org.geysermc.event.PostOrder; import org.geysermc.event.bus.impl.OwnedEventBusImpl; import org.geysermc.event.subscribe.OwnedSubscriber; import org.geysermc.event.subscribe.Subscribe; @@ -43,8 +44,11 @@ public final class GeyserEventBus extends OwnedEventBusImpl> B makeSubscription( - Extension owner, Class eventClass, Subscribe subscribe, - L listener, BiConsumer handler) { + @NonNull Extension owner, + @NonNull Class eventClass, + @NonNull Subscribe subscribe, + @NonNull L listener, + @NonNull BiConsumer handler) { return (B) new GeyserEventSubscriber<>( owner, eventClass, subscribe.postOrder(), subscribe.ignoreCancelled(), listener, handler ); @@ -52,8 +56,11 @@ public final class GeyserEventBus extends OwnedEventBusImpl> B makeSubscription( - Extension owner, Class eventClass, Consumer handler) { - return (B) new GeyserEventSubscriber<>(owner, eventClass, handler); + @NonNull Extension owner, + @NonNull Class eventClass, + @NonNull Consumer handler, + @NonNull PostOrder postOrder) { + return (B) new GeyserEventSubscriber<>(owner, eventClass, handler, postOrder); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java index 6fac82b96..5012037bb 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.event; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.impl.OwnedSubscriberImpl; @@ -36,12 +37,21 @@ import java.util.function.Consumer; public final class GeyserEventSubscriber extends OwnedSubscriberImpl implements ExtensionEventSubscriber { - GeyserEventSubscriber(Extension owner, Class eventClass, Consumer handler) { - super(owner, eventClass, handler); + GeyserEventSubscriber( + @NonNull Extension owner, + @NonNull Class eventClass, + @NonNull Consumer handler, + @NonNull PostOrder postOrder) { + super(owner, eventClass, handler, postOrder); } - GeyserEventSubscriber(Extension owner, Class eventClass, PostOrder postOrder, boolean ignoreCancelled, - H handlerInstance, BiConsumer handler) { + GeyserEventSubscriber( + @NonNull Extension owner, + @NonNull Class eventClass, + @NonNull PostOrder postOrder, + boolean ignoreCancelled, + @NonNull H handlerInstance, + @NonNull BiConsumer handler) { super(owner, eventClass, postOrder, ignoreCancelled, handlerInstance, handler); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java index d1a647be7..7294d4345 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java @@ -27,17 +27,14 @@ package org.geysermc.geyser.extension.event; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; -import org.geysermc.event.bus.impl.EventBusImpl; -import org.geysermc.event.subscribe.Subscribe; +import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.Subscriber; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventSubscriber; import org.geysermc.geyser.api.event.ExtensionEventBus; -import org.geysermc.geyser.api.event.ExtensionEventSubscriber; import org.geysermc.geyser.api.extension.Extension; import java.util.Set; -import java.util.function.BiConsumer; import java.util.function.Consumer; public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) implements ExtensionEventBus { @@ -68,6 +65,16 @@ public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) im return eventBus.subscribe(extension, eventClass, consumer); } + @Override + @SuppressWarnings("unchecked") + public > @NonNull U subscribe( + @NonNull Class eventClass, + @NonNull Consumer consumer, + @NonNull PostOrder postOrder + ) { + return eventBus.subscribe(extension, eventClass, consumer, postOrder); + } + @Override public void unregisterAll() { eventBus.unregisterAll(extension); From 7d7a38a502dce1bc8155eea258e157fc4e376ffd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 3 Sep 2022 14:03:22 -0400 Subject: [PATCH 157/290] Indicate support for 1.19.22 --- README.md | 2 +- .../java/org/geysermc/geyser/network/MinecraftProtocol.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fd253db77..464e67d76 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20/1.19.21 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20/1.19.21/1.19.22 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 98f431d15..cec5c5ce6 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -46,7 +46,7 @@ public final class MinecraftProtocol { * release of the game that Geyser supports. */ public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v544.V544_CODEC.toBuilder() - .minecraftVersion("1.19.21") + .minecraftVersion("1.19.22") .protocolVersion(545) .build(); /** @@ -68,7 +68,9 @@ public final class MinecraftProtocol { .minecraftVersion("1.19.10/1.19.11") .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.21/1.19.22") + .build()); } /** From a16fc9c07c9c6c2c00e03ba5b0637d89f05a1d4d Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Sat, 3 Sep 2022 20:12:48 +0200 Subject: [PATCH 158/290] Add way to specify key for encrypted packs (#3263) --- .../geyser/network/UpstreamPacketHandler.java | 2 +- .../org/geysermc/geyser/pack/ResourcePack.java | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 5ae6fbca9..b4c4ae471 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -106,7 +106,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { ResourcePackManifest.Header header = resourcePack.getManifest().getHeader(); resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( header.getUuid().toString(), header.getVersionString(), resourcePack.getFile().length(), - "", "", "", false, false)); + resourcePack.getContentKey(), "", header.getUuid().toString(), false, false)); } resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks()); session.sendUpstreamPacket(resourcePacksInfo); diff --git a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java index d9f1e36f5..c0913f31c 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java +++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java @@ -26,16 +26,20 @@ package org.geysermc.geyser.pack; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.FileUtils; import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import lombok.Getter; + /** * This represents a resource pack and all the data relevant to it */ @@ -55,6 +59,9 @@ public class ResourcePack { private ResourcePackManifest manifest; private ResourcePackManifest.Version version; + @Getter + private String contentKey; + /** * Loop through the packs directory and locate valid resource pack files */ @@ -97,6 +104,11 @@ public class ResourcePack { } } }); + + // Check if a file exists with the same name as the resource pack suffixed by .key, + // and set this as content key. (e.g. test.zip, key file would be test.zip.key) + File keyFile = new File(file.getParentFile(), file.getName() + ".key"); + pack.contentKey = keyFile.exists() ? Files.readString(keyFile.toPath(), StandardCharsets.UTF_8) : ""; } catch (Exception e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", file.getName())); e.printStackTrace(); From e5337b629828f8531868f2abbe6eeada9653eba8 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 4 Sep 2022 13:08:17 -0500 Subject: [PATCH 159/290] Reintroduce GeyserDefineCommandsEvent and cleanup a few things --- api/base/build.gradle.kts | 7 +- .../main/java/org/geysermc/api/Geyser.java | 4 +- .../org/geysermc/geyser/api/GeyserApi.java | 13 +- .../geysermc/geyser/api/command/Command.java | 39 ++++-- .../lifecycle/GeyserDefineCommandsEvent.java} | 29 ++--- .../event/lifecycle/GeyserShutdownEvent.java | 3 +- .../api/extension/ExtensionDescription.java | 20 ++- .../bungeecord/GeyserBungeePlugin.java | 14 +- .../platform/spigot/GeyserSpigotPlugin.java | 50 ++++++- .../command/GeyserSpigotCommandManager.java | 4 + .../spigot/src/main/resources/plugin.yml | 5 +- .../platform/sponge/GeyserSpongePlugin.java | 13 +- .../velocity/GeyserVelocityPlugin.java | 13 +- .../java/org/geysermc/geyser/GeyserImpl.java | 8 +- .../geyser/command/GeyserCommandManager.java | 122 ++++++++++++------ .../geyser/command/defaults/HelpCommand.java | 6 +- .../type/GeyserDefineCommandsEventImpl.java | 46 +++++++ ... => GeyserDefineCustomItemsEventImpl.java} | 4 +- .../extension/GeyserExtensionDescription.java | 9 +- .../command/GeyserExtensionCommand.java | 43 ++++++ .../loader/ProviderRegistryLoader.java | 5 +- .../populator/ItemRegistryPopulator.java | 5 +- 22 files changed, 355 insertions(+), 107 deletions(-) rename api/geyser/src/main/java/org/geysermc/geyser/api/{command/CommandManager.java => event/lifecycle/GeyserDefineCommandsEvent.java} (68%) create mode 100644 core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java rename core/src/main/java/org/geysermc/geyser/event/type/{DefineCustomItemsEvent.java => GeyserDefineCustomItemsEventImpl.java} (93%) create mode 100644 core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index 03f08c6d2..a6fa608cc 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -1,4 +1,7 @@ dependencies { api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) - api("org.geysermc.event", "events", Versions.eventsVersion) -} + api("org.geysermc.event", "events", Versions.eventsVersion) { + exclude(group = "com.google.guava", module = "guava") + exclude(group = "org.lanternpowered", module = "lmbda") + } +} \ No newline at end of file diff --git a/api/base/src/main/java/org/geysermc/api/Geyser.java b/api/base/src/main/java/org/geysermc/api/Geyser.java index 9f315faf4..d0bdf3b5e 100644 --- a/api/base/src/main/java/org/geysermc/api/Geyser.java +++ b/api/base/src/main/java/org/geysermc/api/Geyser.java @@ -69,7 +69,7 @@ public class Geyser { /** * Registers the given api type. The api cannot be - * registered if {@link #registered()} is true as + * registered if {@link #isRegistered()} is true as * an api has already been specified. * * @param api the api @@ -88,7 +88,7 @@ public class Geyser { * * @return if the api has been registered */ - public static boolean registered() { + public static boolean isRegistered() { return api != null; } } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index 82f0566fe..e73727104 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; import org.geysermc.api.GeyserApiBase; -import org.geysermc.geyser.api.command.CommandManager; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; @@ -66,15 +65,9 @@ public interface GeyserApi extends GeyserApiBase { * * @return the extension manager */ + @NonNull ExtensionManager extensionManager(); - /** - * Gets the {@link CommandManager}. - * - * @return the command manager - */ - CommandManager commandManager(); - /** * Provides an implementation for the specified API type. * @@ -92,6 +85,7 @@ public interface GeyserApi extends GeyserApiBase { * * @return the event bus */ + @NonNull EventBus eventBus(); /** @@ -100,6 +94,7 @@ public interface GeyserApi extends GeyserApiBase { * * @return the default remote server used within Geyser */ + @NonNull RemoteServer defaultRemoteServer(); /** @@ -108,6 +103,7 @@ public interface GeyserApi extends GeyserApiBase { * * @return the listener used for Bedrock client connectins */ + @NonNull BedrockListener bedrockListener(); /** @@ -115,6 +111,7 @@ public interface GeyserApi extends GeyserApiBase { * * @return the current geyser api instance */ + @NonNull static GeyserApi api() { return Geyser.api(GeyserApi.class); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java index 0ad296669..2f1f2b24d 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/Command.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.api.command; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.extension.Extension; import java.util.Collections; import java.util.List; @@ -104,19 +106,39 @@ public interface Command { return false; } - static Command.Builder builder(Class sourceType) { - return GeyserApi.api().provider(Builder.class, sourceType); + /** + * Creates a new {@link Command.Builder} used to construct commands. + * + * @param extension the extension + * @param the source type + * @return a new command builder used to construct commands + */ + static Command.Builder builder(@NonNull Extension extension) { + return GeyserApi.api().provider(Builder.class, extension); } interface Builder { + /** + * Defines the source type to use for this command. + *

+ * Command source types can be anything that extend + * {@link CommandSource}, such as {@link GeyserConnection}. + * This will guarantee that the source used in the executor + * is an instance of this source. + * + * @param sourceType the source type + * @return the builder + */ + Builder source(@NonNull Class sourceType); + /** * Sets the command name. * * @param name the command name * @return the builder */ - Builder name(String name); + Builder name(@NonNull String name); /** * Sets the command description. @@ -124,7 +146,7 @@ public interface Command { * @param description the command description * @return the builder */ - Builder description(String description); + Builder description(@NonNull String description); /** * Sets the permission node. @@ -132,7 +154,7 @@ public interface Command { * @param permission the permission node * @return the builder */ - Builder permission(String permission); + Builder permission(@NonNull String permission); /** * Sets the aliases. @@ -140,7 +162,7 @@ public interface Command { * @param aliases the aliases * @return the builder */ - Builder aliases(List aliases); + Builder aliases(@NonNull List aliases); /** * Sets if this command is designed to be used only by server operators. @@ -164,7 +186,7 @@ public interface Command { * @param subCommands the subcommands * @return the builder */ - Builder subCommands(List subCommands); + Builder subCommands(@NonNull List subCommands); /** * Sets if this command is bedrock only. @@ -180,13 +202,14 @@ public interface Command { * @param executor the command executor * @return the builder */ - Builder executor(CommandExecutor executor); + Builder executor(@NonNull CommandExecutor executor); /** * Builds the command. * * @return the command */ + @NonNull Command build(); } } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java similarity index 68% rename from api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java index 9f29651ba..77d5efa65 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandManager.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCommandsEvent.java @@ -23,36 +23,35 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.command; +package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.event.Event; +import org.geysermc.geyser.api.command.Command; import java.util.Map; /** - * Manages Bedrock commands within Geyser. + * Called when commands are defined within Geyser. + * + * This event allows you to register new commands using the {@link #register(Command)} + * method and retrieve the default commands defined. */ -public abstract class CommandManager { +public interface GeyserDefineCommandsEvent extends Event { /** - * Registers the given {@link Command}. + * Registers the given {@link Command} into the Geyser + * command manager. * * @param command the command to register */ - public abstract void register(@NonNull Command command); + void register(@NonNull Command command); /** - * Unregisters the given {@link Command}. + * Gets all the registered built-in {@link Command}s. * - * @param command the command to unregister - */ - public abstract void unregister(@NonNull Command command); - - /** - * Gets all the registered {@link Command}s. - * - * @return all the registered commands + * @return all the registered built-in commands */ @NonNull - public abstract Map commands(); + Map commands(); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java index f2fab901d..a1c68d876 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java @@ -27,12 +27,11 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; -import org.geysermc.geyser.api.command.CommandManager; import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.extension.ExtensionManager; /** * Called when Geyser is shutting down. */ -public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull CommandManager commandManager, @NonNull EventBus eventBus) implements Event { +public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index e77411144..8136bd761 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -30,12 +30,20 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.util.List; /** - * This is the Geyser extension description + * Represents the description of an {@link Extension}. */ public interface ExtensionDescription { /** - * Gets the extension's name + * Gets the extension's id. + * + * @return the extension's id + */ + @NonNull + String id(); + + /** + * Gets the extension's name. * * @return the extension's name */ @@ -43,7 +51,7 @@ public interface ExtensionDescription { String name(); /** - * Gets the extension's main class + * Gets the extension's main class. * * @return the extension's main class */ @@ -51,7 +59,7 @@ public interface ExtensionDescription { String main(); /** - * Gets the extension's api version + * Gets the extension's api version. * * @return the extension's api version */ @@ -59,7 +67,7 @@ public interface ExtensionDescription { String apiVersion(); /** - * Gets the extension's description + * Gets the extension's description. * * @return the extension's description */ @@ -67,7 +75,7 @@ public interface ExtensionDescription { String version(); /** - * Gets the extension's authors + * Gets the extension's authors. * * @return the extension's authors */ diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index c72503450..ed2c340db 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -32,6 +32,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -49,6 +51,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; import java.util.UUID; import java.util.logging.Level; @@ -149,8 +152,15 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy()); } - this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", geyser, geyserCommandManager.getCommands())); - this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyserext", geyser, geyserCommandManager.commands())); + this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands())); + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(entry.getKey().description().id(), this.geyser, commands)); + } } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 4a371cfe8..e3b794578 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -32,9 +32,11 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import io.netty.buffer.ByteBuf; import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; +import org.bukkit.command.CommandMap; import org.bukkit.command.PluginCommand; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; import org.geysermc.geyser.Constants; @@ -42,6 +44,7 @@ import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -62,6 +65,8 @@ import org.geysermc.geyser.util.FileUtils; import java.io.File; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.net.SocketAddress; import java.nio.file.Path; import java.util.List; @@ -269,13 +274,32 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { PluginCommand geyserCommand = this.getCommand("geyser"); geyserCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands())); - PluginCommand geyserExtCommand = this.getCommand("geyserext"); - geyserExtCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands())); + + CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + // Thanks again, Bukkit + try { + Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + constructor.setAccessible(true); + + PluginCommand pluginCommand = constructor.newInstance(entry.getKey().description().id(), this); + pluginCommand.setExecutor(new GeyserSpigotCommandExecutor(this.geyser, commands)); + pluginCommand.setDescription("The main command for the " + entry.getKey().name() + " Geyser extension!"); + commandMap.register(entry.getKey().description().id(), "geyserext", pluginCommand); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { + this.geyserLogger.error("Failed to construct PluginCommand for extension " + entry.getKey().description().name(), ex); + } + } if (!INITIALIZED) { // Register permissions so they appear in, for example, LuckPerms' UI // Re-registering permissions throws an error - for (Map.Entry entry : geyserCommandManager.getCommands().entrySet()) { + for (Map.Entry entry : geyserCommandManager.commands().entrySet()) { Command command = entry.getValue(); if (command.aliases().contains(entry.getKey())) { // Don't register aliases @@ -286,6 +310,26 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { GeyserLocale.getLocaleStringLog(command.description()), command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); } + + // Register permissions for extension commands + for (Map.Entry> commandEntry : this.geyserCommandManager.extensionCommands().entrySet()) { + for (Map.Entry entry : commandEntry.getValue().entrySet()) { + Command command = entry.getValue(); + if (command.aliases().contains(entry.getKey())) { + // Don't register aliases + continue; + } + + if (command.permission().isBlank()) { + continue; + } + + Bukkit.getPluginManager().addPermission(new Permission(command.permission(), + GeyserLocale.getLocaleStringLog(command.description()), + command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); + } + } + Bukkit.getPluginManager().addPermission(new Permission(Constants.UPDATE_PERMISSION, "Whether update notifications can be seen", PermissionDefault.OP)); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java index 9fb19f0da..655d3be23 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java @@ -65,4 +65,8 @@ public class GeyserSpigotCommandManager extends GeyserCommandManager { Command cmd = COMMAND_MAP.getCommand(command.replace("/", "")); return cmd != null ? cmd.getDescription() : ""; } + + public static CommandMap getCommandMap() { + return COMMAND_MAP; + } } diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index 0f6398b49..e28b8981d 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -8,7 +8,4 @@ api-version: 1.13 commands: geyser: description: The main command for Geyser. - usage: /geyser - geyserext: - description: The command any extensions can register to. - usage: /geyserext \ No newline at end of file + usage: /geyser \ No newline at end of file diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index 312dfb087..d912d28d8 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -29,6 +29,8 @@ import com.google.inject.Inject; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; @@ -50,6 +52,7 @@ import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.file.Path; +import java.util.Map; import java.util.UUID; @Plugin(id = "geyser", name = GeyserImpl.NAME + "-Sponge", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") @@ -122,7 +125,15 @@ public class GeyserSpongePlugin implements GeyserBootstrap { this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser); this.geyserCommandManager.init(); Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); - Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.commands()), "geyserext"); + + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id()); + } } @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index e2f84a2a7..30d8deccd 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -39,6 +39,8 @@ import net.kyori.adventure.util.Codec; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -58,6 +60,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; import java.util.UUID; @Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") @@ -159,7 +162,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserCommandManager.init(); this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.getCommands())); - this.commandManager.register("geyserext", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.commands())); + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + this.commandManager.register(entry.getKey().description().id(), new GeyserVelocityCommandExecutor(this.geyser, commands)); + } + if (geyserConfig.isLegacyPingPassthrough()) { this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); } else { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index ed65ffbe9..24a5f5d2c 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -547,7 +547,7 @@ public class GeyserImpl implements GeyserApi { ResourcePack.PACKS.clear(); - this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.commandManager(), this.eventBus)); + this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus)); this.extensionManager.disableExtensions(); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); @@ -572,11 +572,12 @@ public class GeyserImpl implements GeyserApi { } @Override + @NonNull public GeyserExtensionManager extensionManager() { return this.extensionManager; } - @Override + @NonNull public GeyserCommandManager commandManager() { return this.bootstrap.getGeyserCommandManager(); } @@ -587,15 +588,18 @@ public class GeyserImpl implements GeyserApi { } @Override + @NonNull public EventBus eventBus() { return this.eventBus; } + @NonNull public RemoteServer defaultRemoteServer() { return getConfig().getRemote(); } @Override + @NonNull public BedrockListener bedrockListener() { return getConfig().getBedrock(); } diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java index cb3cf6eee..7c5bd6580 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java @@ -33,30 +33,46 @@ import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.CommandExecutor; -import org.geysermc.geyser.api.command.CommandManager; import org.geysermc.geyser.api.command.CommandSource; -import org.geysermc.geyser.command.defaults.*; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand; +import org.geysermc.geyser.command.defaults.AdvancementsCommand; +import org.geysermc.geyser.command.defaults.ConnectionTestCommand; +import org.geysermc.geyser.command.defaults.DumpCommand; +import org.geysermc.geyser.command.defaults.ExtensionsCommand; +import org.geysermc.geyser.command.defaults.HelpCommand; +import org.geysermc.geyser.command.defaults.ListCommand; +import org.geysermc.geyser.command.defaults.OffhandCommand; +import org.geysermc.geyser.command.defaults.ReloadCommand; +import org.geysermc.geyser.command.defaults.SettingsCommand; +import org.geysermc.geyser.command.defaults.StatisticsCommand; +import org.geysermc.geyser.command.defaults.StopCommand; +import org.geysermc.geyser.command.defaults.VersionCommand; +import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl; +import org.geysermc.geyser.extension.command.GeyserExtensionCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @RequiredArgsConstructor -public abstract class GeyserCommandManager extends CommandManager { +public abstract class GeyserCommandManager { @Getter private final Map commands = new Object2ObjectOpenHashMap<>(12); - private final Map extensionCommands = new Object2ObjectOpenHashMap<>(0); + private final Map> extensionCommands = new Object2ObjectOpenHashMap<>(0); private final GeyserImpl geyser; public void init() { - registerBuiltInCommand(new HelpCommand(geyser, "help", "geyser.commands.help.desc", "geyser.command.help", "geyser", commands)); + registerBuiltInCommand(new HelpCommand(geyser, "help", "geyser.commands.help.desc", "geyser.command.help", "geyser", this.commands)); registerBuiltInCommand(new ListCommand(geyser, "list", "geyser.commands.list.desc", "geyser.command.list")); registerBuiltInCommand(new ReloadCommand(geyser, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); registerBuiltInCommand(new OffhandCommand(geyser, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); @@ -67,11 +83,32 @@ public abstract class GeyserCommandManager extends CommandManager { registerBuiltInCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); registerBuiltInCommand(new AdvancedTooltipsCommand("tooltips", "geyser.commands.advancedtooltips.desc", "geyser.command.tooltips")); registerBuiltInCommand(new ConnectionTestCommand(geyser, "connectiontest", "geyser.commands.connectiontest.desc", "geyser.command.connectiontest")); - if (GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE) { + if (this.geyser.getPlatformType() == PlatformType.STANDALONE) { registerBuiltInCommand(new StopCommand(geyser, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); } - register(new HelpCommand(geyser, "help", "geyser.commands.exthelp.desc", "geyser.command.exthelp", "geyserext", extensionCommands)); + if (this.geyser.extensionManager().extensions().size() > 0) { + registerBuiltInCommand(new ExtensionsCommand(this.geyser, "extensions", "geyser.commands.extensions.desc", "geyser.command.extensions")); + } + + GeyserDefineCommandsEvent defineCommandsEvent = new GeyserDefineCommandsEventImpl(this.commands) { + + @Override + public void register(@NonNull Command command) { + if (!(command instanceof GeyserExtensionCommand extensionCommand)) { + throw new IllegalArgumentException("Expected GeyserExtensionCommand as part of command registration but got " + command + "! Did you use the Command builder properly?"); + } + + registerExtensionCommand(extensionCommand.extension(), extensionCommand); + } + }; + + this.geyser.eventBus().fire(defineCommandsEvent); + + // Register help commands for all extensions with commands + for (Map.Entry> entry : this.extensionCommands.entrySet()) { + registerExtensionCommand(entry.getKey(), new HelpCommand(this.geyser, "help", "geyser.commands.exthelp.desc", "geyser.command.exthelp", entry.getKey().description().id(), entry.getValue())); + } } /** @@ -81,9 +118,8 @@ public abstract class GeyserCommandManager extends CommandManager { register(command, this.commands); } - @Override - public void register(@NonNull Command command) { - register(command, this.extensionCommands); + public void registerExtensionCommand(@NonNull Extension extension, @NonNull Command command) { + register(command, this.extensionCommands.computeIfAbsent(extension, e -> new HashMap<>())); } private void register(Command command, Map commands) { @@ -99,32 +135,30 @@ public abstract class GeyserCommandManager extends CommandManager { } } - @Override - public void unregister(@NonNull Command command) { - this.extensionCommands.remove(command.name(), command); - - if (command.aliases().isEmpty()) { - return; - } - - for (String alias : command.aliases()) { - this.extensionCommands.remove(alias, command); - } + @NotNull + public Map commands() { + return Collections.unmodifiableMap(this.commands); } @NotNull - @Override - public Map commands() { + public Map> extensionCommands() { return Collections.unmodifiableMap(this.extensionCommands); } public boolean runCommand(GeyserCommandSource sender, String command) { - boolean extensionCommand = command.startsWith("geyserext "); - if (!command.startsWith("geyser ") && !extensionCommand) { + Extension extension = null; + for (Extension loopedExtension : this.extensionCommands.keySet()) { + if (command.startsWith(loopedExtension.description().id() + " ")) { + extension = loopedExtension; + break; + } + } + + if (!command.startsWith("geyser ") && extension == null) { return false; } - command = command.trim().replace(extensionCommand ? "geyserext " : "geyser ", ""); + command = command.trim().replace(extension != null ? extension.description().id() + " " : "geyser ", ""); String label; String[] args; @@ -137,9 +171,9 @@ public abstract class GeyserCommandManager extends CommandManager { args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine }; } - Command cmd = (extensionCommand ? this.extensionCommands : this.commands).get(label); + Command cmd = (extension != null ? this.extensionCommands.getOrDefault(extension, Collections.emptyMap()) : this.commands).get(label); if (cmd == null) { - geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.invalid")); + sender.sendMessage(GeyserLocale.getLocaleStringLog("geyser.commands.invalid")); return false; } @@ -168,7 +202,8 @@ public abstract class GeyserCommandManager extends CommandManager { @RequiredArgsConstructor public static class CommandBuilder implements Command.Builder { - private final Class sourceType; + private final Extension extension; + private Class sourceType; private String name; private String description = ""; private String permission = ""; @@ -179,22 +214,28 @@ public abstract class GeyserCommandManager extends CommandManager { private boolean bedrockOnly; private CommandExecutor executor; - public CommandBuilder name(String name) { + @Override + public Command.Builder source(@NonNull Class sourceType) { + this.sourceType = sourceType; + return this; + } + + public CommandBuilder name(@NonNull String name) { this.name = name; return this; } - public CommandBuilder description(String description) { + public CommandBuilder description(@NonNull String description) { this.description = description; return this; } - public CommandBuilder permission(String permission) { + public CommandBuilder permission(@NonNull String permission) { this.permission = permission; return this; } - public CommandBuilder aliases(List aliases) { + public CommandBuilder aliases(@NonNull List aliases) { this.aliases = aliases; return this; } @@ -210,7 +251,7 @@ public abstract class GeyserCommandManager extends CommandManager { return this; } - public CommandBuilder subCommands(List subCommands) { + public CommandBuilder subCommands(@NonNull List subCommands) { this.subCommands = subCommands; return this; } @@ -220,22 +261,27 @@ public abstract class GeyserCommandManager extends CommandManager { return this; } - public CommandBuilder executor(CommandExecutor executor) { + public CommandBuilder executor(@NonNull CommandExecutor executor) { this.executor = executor; return this; } - public GeyserCommand build() { + @NonNull + public GeyserExtensionCommand build() { if (this.name == null || this.name.isBlank()) { throw new IllegalArgumentException("Command cannot be null or blank!"); } - return new GeyserCommand(this.name, this.description, this.permission) { + if (this.sourceType == null) { + throw new IllegalArgumentException("Source type was not defined for command " + this.name + " in extension " + this.extension.name()); + } + + return new GeyserExtensionCommand(this.extension, this.name, this.description, this.permission) { @SuppressWarnings("unchecked") @Override public void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args) { - Class sourceType = CommandBuilder.this.sourceType; + Class sourceType = CommandBuilder.this.sourceType; CommandExecutor executor = CommandBuilder.this.executor; if (sourceType.isInstance(session)) { executor.execute((T) session, this, args); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java index 81f34b759..6e7ad2f04 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java @@ -66,19 +66,19 @@ public class HelpCommand extends GeyserCommand { String header = GeyserLocale.getPlayerLocaleString("geyser.commands.help.header", sender.locale(), page, maxPage); sender.sendMessage(header); - for (Map.Entry entry : commands.entrySet()) { + this.commands.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> { Command cmd = entry.getValue(); // Standalone hack-in since it doesn't have a concept of permissions if (geyser.getPlatformType() == PlatformType.STANDALONE || sender.hasPermission(cmd.permission())) { // Only list commands the player can actually run if (cmd.isBedrockOnly() && session == null) { - continue; + return; } sender.sendMessage(ChatColor.YELLOW + "/" + baseCommand + " " + entry.getKey() + ChatColor.WHITE + ": " + GeyserLocale.getPlayerLocaleString(cmd.description(), sender.locale())); } - } + }); } } diff --git a/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java new file mode 100644 index 000000000..e07a62d8a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCommandsEventImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.event.type; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; + +import java.util.Collections; +import java.util.Map; + +public abstract class GeyserDefineCommandsEventImpl implements GeyserDefineCommandsEvent { + private final Map commands; + + public GeyserDefineCommandsEventImpl(Map commands) { + this.commands = commands; + } + + @Override + public @NonNull Map commands() { + return Collections.unmodifiableMap(this.commands); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCustomItemsEventImpl.java similarity index 93% rename from core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java rename to core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCustomItemsEventImpl.java index 9011bfb3a..65fd7ea0d 100644 --- a/core/src/main/java/org/geysermc/geyser/event/type/DefineCustomItemsEvent.java +++ b/core/src/main/java/org/geysermc/geyser/event/type/GeyserDefineCustomItemsEventImpl.java @@ -36,11 +36,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; -public abstract class DefineCustomItemsEvent implements GeyserDefineCustomItemsEvent { +public abstract class GeyserDefineCustomItemsEventImpl implements GeyserDefineCustomItemsEvent { private final Multimap customItems; private final List nonVanillaCustomItems; - public DefineCustomItemsEvent(Multimap customItems, List nonVanillaCustomItems) { + public GeyserDefineCustomItemsEventImpl(Multimap customItems, List nonVanillaCustomItems) { this.customItems = customItems; this.nonVanillaCustomItems = nonVanillaCustomItems; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index eaf29a819..04f80e19d 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -33,7 +33,7 @@ import org.yaml.snakeyaml.Yaml; import java.io.Reader; import java.util.*; -public record GeyserExtensionDescription(String name, String main, String apiVersion, String version, List authors) implements ExtensionDescription { +public record GeyserExtensionDescription(String id, String name, String main, String apiVersion, String version, List authors) implements ExtensionDescription { @SuppressWarnings("unchecked") public static GeyserExtensionDescription fromYaml(Reader reader) throws InvalidDescriptionException { DumperOptions dumperOptions = new DumperOptions(); @@ -42,6 +42,11 @@ public record GeyserExtensionDescription(String name, String main, String apiVer Yaml yaml = new Yaml(dumperOptions); Map yamlMap = yaml.loadAs(reader, LinkedHashMap.class); + String id = ((String) yamlMap.get("id")).replaceAll("[^A-Za-z0-9 _.-]", ""); + if (id.isBlank()) { + throw new InvalidDescriptionException("Invalid extension id, cannot be empty"); + } + String name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); if (name.isBlank()) { throw new InvalidDescriptionException("Invalid extension name, cannot be empty"); @@ -72,6 +77,6 @@ public record GeyserExtensionDescription(String name, String main, String apiVer } } - return new GeyserExtensionDescription(name, main, apiVersion, version, authors); + return new GeyserExtensionDescription(id, name, main, apiVersion, version, Collections.unmodifiableList(authors)); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java new file mode 100644 index 000000000..4a7830c90 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension.command; + +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.command.GeyserCommand; + +public abstract class GeyserExtensionCommand extends GeyserCommand { + private final Extension extension; + + public GeyserExtensionCommand(Extension extension, String name, String description, String permission) { + super(name, description, permission); + + this.extension = extension; + } + + public Extension extension() { + return this.extension; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java index 449f6574e..e7837688c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.loader; import org.geysermc.geyser.api.command.Command; -import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; @@ -43,10 +43,9 @@ import java.util.Map; */ public class ProviderRegistryLoader implements RegistryLoader, ProviderSupplier>, Map, ProviderSupplier>> { - @SuppressWarnings("unchecked") @Override public Map, ProviderSupplier> load(Map, ProviderSupplier> providers) { - providers.put(Command.Builder.class, args -> new GeyserCommandManager.CommandBuilder<>((Class) args[0])); + providers.put(Command.Builder.class, args -> new GeyserCommandManager.CommandBuilder<>((Extension) args[0])); providers.put(CustomItemData.Builder.class, args -> new GeyserCustomItemData.CustomItemDataBuilder()); providers.put(CustomItemOptions.Builder.class, args -> new GeyserCustomItemOptions.CustomItemOptionsBuilder()); providers.put(NonVanillaCustomItemData.Builder.class, args -> new GeyserNonVanillaCustomItemData.NonVanillaCustomItemDataBuilder()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index e6d1cb3e4..60a16245c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -48,11 +48,10 @@ import it.unimi.dsi.fastutil.objects.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomItemsEvent; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; -import org.geysermc.geyser.event.type.DefineCustomItemsEvent; +import org.geysermc.geyser.event.type.GeyserDefineCustomItemsEventImpl; import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.mappings.MappingsConfigReader; @@ -109,7 +108,7 @@ public class ItemRegistryPopulator { }); nonVanillaCustomItems = new ObjectArrayList<>(); - GeyserImpl.getInstance().eventBus().fire(new DefineCustomItemsEvent(customItems, nonVanillaCustomItems) { + GeyserImpl.getInstance().eventBus().fire(new GeyserDefineCustomItemsEventImpl(customItems, nonVanillaCustomItems) { @Override public boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData) { if (CustomItemRegistryPopulator.initialCheck(identifier, customItemData, items)) { From f1da9d70728ad50cbff5c345052f8b18fabb06f2 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+imdabigboss@users.noreply.github.com> Date: Sun, 4 Sep 2022 16:11:08 -0500 Subject: [PATCH 160/290] Allow events to be registered by any class Supersedes & closes #3073 Co-authored-by: Redned --- .../main/java/org/geysermc/api/Geyser.java | 1 + .../geysermc/api/util/BedrockPlatform.java | 3 + .../java/org/geysermc/api/util/InputMode.java | 3 + .../java/org/geysermc/api/util/UiProfile.java | 3 + .../org/geysermc/geyser/api/GeyserApi.java | 3 +- .../geysermc/geyser/api/event/EventBus.java | 4 +- .../geyser/api/event/EventRegistrar.java | 45 ++++++++ .../geyser/api/event/EventSubscriber.java | 2 +- .../geyser/api/event/ExtensionEventBus.java | 5 +- .../GeyserDefineCustomItemsEvent.java | 2 + .../lifecycle/GeyserPostInitializeEvent.java | 3 +- .../lifecycle/GeyserPreInitializeEvent.java | 3 +- .../event/lifecycle/GeyserShutdownEvent.java | 3 +- .../geyser/api/extension/Extension.java | 15 ++- .../bungeecord/GeyserBungeePlugin.java | 88 ++++++++++---- .../platform/spigot/GeyserSpigotPlugin.java | 108 ++++++++++++------ .../platform/sponge/GeyserSpongePlugin.java | 17 ++- .../standalone/GeyserStandaloneBootstrap.java | 4 +- .../velocity/GeyserVelocityPlugin.java | 36 +++--- .../java/org/geysermc/geyser/GeyserImpl.java | 46 +++++--- .../geysermc/geyser/event/GeyserEventBus.java | 15 +-- .../geyser/event/GeyserEventRegistrar.java | 38 ++++++ .../geyser/event/GeyserEventSubscriber.java | 7 +- .../event/GeyserExtensionEventBus.java | 11 +- .../loader/ProviderRegistryLoader.java | 3 + 25 files changed, 353 insertions(+), 115 deletions(-) create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java create mode 100644 core/src/main/java/org/geysermc/geyser/event/GeyserEventRegistrar.java diff --git a/api/base/src/main/java/org/geysermc/api/Geyser.java b/api/base/src/main/java/org/geysermc/api/Geyser.java index d0bdf3b5e..7543d1661 100644 --- a/api/base/src/main/java/org/geysermc/api/Geyser.java +++ b/api/base/src/main/java/org/geysermc/api/Geyser.java @@ -39,6 +39,7 @@ public class Geyser { * * @return the base api */ + @NonNull public static GeyserApiBase api() { if (api == null) { throw new RuntimeException("Api has not been registered yet!"); diff --git a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java index d66077a87..e486f73bc 100644 --- a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java +++ b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java @@ -25,6 +25,8 @@ package org.geysermc.api.util; +import org.checkerframework.checker.nullness.qual.NonNull; + public enum BedrockPlatform { UNKNOWN("Unknown"), GOOGLE("Android"), @@ -56,6 +58,7 @@ public enum BedrockPlatform { * @param id the BedrockPlatform identifier * @return The BedrockPlatform or {@link #UNKNOWN} if the platform wasn't found */ + @NonNull public static BedrockPlatform fromId(int id) { return id < VALUES.length ? VALUES[id] : VALUES[0]; } diff --git a/api/base/src/main/java/org/geysermc/api/util/InputMode.java b/api/base/src/main/java/org/geysermc/api/util/InputMode.java index eadb457ab..70346ffa5 100644 --- a/api/base/src/main/java/org/geysermc/api/util/InputMode.java +++ b/api/base/src/main/java/org/geysermc/api/util/InputMode.java @@ -25,6 +25,8 @@ package org.geysermc.api.util; +import org.checkerframework.checker.nullness.qual.NonNull; + public enum InputMode { UNKNOWN, KEYBOARD_MOUSE, @@ -40,6 +42,7 @@ public enum InputMode { * @param id the InputMode identifier * @return The InputMode or {@link #UNKNOWN} if the mode wasn't found */ + @NonNull public static InputMode fromId(int id) { return VALUES.length > id ? VALUES[id] : VALUES[0]; } diff --git a/api/base/src/main/java/org/geysermc/api/util/UiProfile.java b/api/base/src/main/java/org/geysermc/api/util/UiProfile.java index c28ff869c..cddb97260 100644 --- a/api/base/src/main/java/org/geysermc/api/util/UiProfile.java +++ b/api/base/src/main/java/org/geysermc/api/util/UiProfile.java @@ -25,6 +25,8 @@ package org.geysermc.api.util; +import org.checkerframework.checker.nullness.qual.NonNull; + public enum UiProfile { CLASSIC, POCKET; @@ -36,6 +38,7 @@ public enum UiProfile { * @param id the UiProfile identifier * @return The UiProfile or {@link #CLASSIC} if the profile wasn't found */ + @NonNull public static UiProfile fromId(int id) { return VALUES.length > id ? VALUES[id] : VALUES[0]; } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index e73727104..f86206d36 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -31,6 +31,7 @@ import org.geysermc.api.Geyser; import org.geysermc.api.GeyserApiBase; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.ExtensionManager; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; @@ -86,7 +87,7 @@ public interface GeyserApi extends GeyserApiBase { * @return the event bus */ @NonNull - EventBus eventBus(); + EventBus eventBus(); /** * Gets the default {@link RemoteServer} configured diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java index c42698d47..801bfa45f 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventBus.java @@ -36,8 +36,8 @@ import java.util.Set; * Represents a bus capable of subscribing * or "listening" to events and firing them. */ -public interface EventBus extends OwnedEventBus> { +public interface EventBus extends OwnedEventBus> { @Override @NonNull - Set> subscribers(@NonNull Class eventClass); + Set> subscribers(@NonNull Class eventClass); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java new file mode 100644 index 000000000..7a2cc0071 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event; + +import org.geysermc.geyser.api.GeyserApi; + +/** + * Represents an owner for an event that allows it + * to be registered through an {@link EventBus}. + */ +public interface EventRegistrar { + + /** + * Creates an {@link EventRegistrar} instance. + * + * @param object the object to wrap around + * @return an event registrar instance + */ + static EventRegistrar of(Object object) { + return GeyserApi.api().provider(EventRegistrar.class, object); + } +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java index 7ce5b7883..7f91d09a3 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventSubscriber.java @@ -36,5 +36,5 @@ import org.geysermc.geyser.api.extension.Extension; * * @param the class of the event */ -public interface EventSubscriber extends OwnedSubscriber { +public interface EventSubscriber extends OwnedSubscriber { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java index 172c0f9de..a58d35891 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/ExtensionEventBus.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.api.event; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; +import org.geysermc.geyser.api.extension.Extension; import java.util.Set; @@ -34,7 +35,7 @@ import java.util.Set; * An {@link EventBus} with additional methods that implicitly * set the extension instance. */ -public interface ExtensionEventBus extends org.geysermc.event.bus.EventBus> { +public interface ExtensionEventBus extends org.geysermc.event.bus.EventBus> { @Override - @NonNull Set> subscribers(@NonNull Class eventClass); + @NonNull Set> subscribers(@NonNull Class eventClass); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java index bfed5d534..0957b8551 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java @@ -45,6 +45,7 @@ public interface GeyserDefineCustomItemsEvent extends Event { * * @return a multimap of all the already registered custom items */ + @NonNull Map> getExistingCustomItems(); /** @@ -52,6 +53,7 @@ public interface GeyserDefineCustomItemsEvent extends Event { * * @return the list of the already registered non-vanilla custom items */ + @NonNull List getExistingNonVanillaCustomItems(); /** diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java index 9e88c017b..8d145f615 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPostInitializeEvent.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.ExtensionManager; /** @@ -36,5 +37,5 @@ import org.geysermc.geyser.api.extension.ExtensionManager; * @param extensionManager the extension manager * @param eventBus the event bus */ -public record GeyserPostInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { +public record GeyserPostInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java index 2be0272dc..8be89dafd 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserPreInitializeEvent.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.ExtensionManager; /** @@ -36,5 +37,5 @@ import org.geysermc.geyser.api.extension.ExtensionManager; * @param extensionManager the extension manager * @param eventBus the event bus */ -public record GeyserPreInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { +public record GeyserPreInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java index a1c68d876..7793ef997 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserShutdownEvent.java @@ -28,10 +28,11 @@ package org.geysermc.geyser.api.event.lifecycle; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.ExtensionManager; /** * Called when Geyser is shutting down. */ -public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { +public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event { } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java index 2982a76fb..8d4e4da64 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java @@ -25,16 +25,19 @@ package org.geysermc.geyser.api.extension; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.GeyserApiBase; import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.ExtensionEventBus; import java.nio.file.Path; +import java.util.Objects; /** * Represents an extension within Geyser. */ -public interface Extension { +public interface Extension extends EventRegistrar { /** * Gets if the extension is enabled @@ -59,6 +62,7 @@ public interface Extension { * * @return the extension's data folder */ + @NonNull default Path dataFolder() { return this.extensionLoader().dataFolder(this); } @@ -68,6 +72,7 @@ public interface Extension { * * @return the extension event bus */ + @NonNull default ExtensionEventBus eventBus() { return this.extensionLoader().eventBus(this); } @@ -77,6 +82,7 @@ public interface Extension { * * @return the extension manager */ + @NonNull default ExtensionManager extensionManager() { return this.geyserApi().extensionManager(); } @@ -86,6 +92,7 @@ public interface Extension { * * @return the extension's name */ + @NonNull default String name() { return this.description().name(); } @@ -95,6 +102,7 @@ public interface Extension { * * @return the extension's description */ + @NonNull default ExtensionDescription description() { return this.extensionLoader().description(this); } @@ -104,6 +112,7 @@ public interface Extension { * * @return the extension's logger */ + @NonNull default ExtensionLogger logger() { return this.extensionLoader().logger(this); } @@ -113,8 +122,9 @@ public interface Extension { * * @return the extension loader */ + @NonNull default ExtensionLoader extensionLoader() { - return this.extensionManager().extensionLoader(this); + return Objects.requireNonNull(this.extensionManager().extensionLoader(this)); } /** @@ -122,6 +132,7 @@ public interface Extension { * * @return the geyser api instance */ + @NonNull default GeyserApi geyserApi() { return GeyserApi.api(); } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index ed2c340db..eb2a3b9c4 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.platform.bungeecord; +import io.netty.channel.Channel; +import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.protocol.ProtocolConstants; @@ -47,12 +49,15 @@ import org.geysermc.geyser.util.FileUtils; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collection; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { @@ -66,23 +71,9 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { private GeyserImpl geyser; @Override - public void onEnable() { + public void onLoad() { GeyserLocale.init(this); - // Copied from ViaVersion. - // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 - try { - ProtocolConstants.class.getField("MINECRAFT_1_19_1"); - } catch (NoSuchFieldException e) { - getLogger().warning(" / \\"); - getLogger().warning(" / \\"); - getLogger().warning(" / | \\"); - getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); - getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); - getLogger().warning(" / o \\"); - getLogger().warning("/_____________\\"); - } - if (!getDataFolder().exists()) getDataFolder().mkdir(); @@ -121,6 +112,25 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); + } + + @Override + public void onEnable() { + // Copied from ViaVersion. + // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 + try { + ProtocolConstants.class.getField("MINECRAFT_1_19_1"); + } catch (NoSuchFieldException e) { + getLogger().warning(" / \\"); + getLogger().warning(" / \\"); + getLogger().warning(" / | \\"); + getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); + getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + getLogger().warning(" / o \\"); + getLogger().warning("/_____________\\"); + } + // Remove this in like a year if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/")); @@ -138,7 +148,41 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { geyserConfig.loadFloodgate(this); - this.geyser = GeyserImpl.start(PlatformType.BUNGEECORD, this); + // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating + // task that waits for a field to be filled which is set after the plugin enable + // process is complete + this.awaitStartupCompletion(0); + } + + @SuppressWarnings("unchecked") + private void awaitStartupCompletion(int tries) { + // After 20 tries give up waiting. This will happen + // just after 3 minutes approximately + if (tries >= 20) { + this.geyserLogger.warning("BungeeCord plugin startup is taking abnormally long, so Geyser is starting now. " + + "If all your plugins are loaded properly, this is a bug! " + + "If not, consider cutting down the amount of plugins on your proxy as it is causing abnormally slow starting times."); + this.postStartup(); + return; + } + + try { + Field listenersField = BungeeCord.getInstance().getClass().getDeclaredField("listeners"); + listenersField.setAccessible(true); + + Collection listeners = (Collection) listenersField.get(BungeeCord.getInstance()); + if (!listeners.isEmpty()) { + this.getProxy().getScheduler().schedule(this, this::postStartup, tries, TimeUnit.SECONDS); + } else { + this.awaitStartupCompletion(++tries); + } + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + } + } + + private void postStartup() { + GeyserImpl.start(); this.geyserInjector = new GeyserBungeeInjector(this); this.geyserInjector.initializeLocalChannel(this); @@ -146,12 +190,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserCommandManager = new GeyserBungeeCommandManager(geyser); this.geyserCommandManager.init(); - if (geyserConfig.isLegacyPingPassthrough()) { - this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser); - } else { - this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy()); - } - this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands())); for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { Map commands = entry.getValue(); @@ -161,6 +199,12 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(entry.getKey().description().id(), this.geyser, commands)); } + + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser); + } else { + this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy()); + } } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index e3b794578..2000dc114 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -34,6 +34,9 @@ import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; import org.bukkit.command.CommandMap; import org.bukkit.command.PluginCommand; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServerLoadEvent; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.Plugin; @@ -59,7 +62,12 @@ import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; -import org.geysermc.geyser.platform.spigot.world.manager.*; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigot1_12NativeWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigot1_12WorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotFallbackWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotLegacyNativeWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -95,7 +103,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { private String minecraftVersion; @Override - public void onEnable() { + public void onLoad() { GeyserLocale.init(this); // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed @@ -113,6 +121,30 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } + // By default this should be localhost but may need to be changed in some circumstances + if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { + geyserConfig.setAutoconfiguredRemote(true); + // Don't use localhost if not listening on all interfaces + if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { + geyserConfig.getRemote().setAddress(Bukkit.getIp()); + } + geyserConfig.getRemote().setPort(Bukkit.getPort()); + } + + if (geyserConfig.getBedrock().isCloneRemotePort()) { + geyserConfig.getBedrock().setPort(Bukkit.getPort()); + } + + this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) + : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); + + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + + this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this); + } + + @Override + public void onEnable() { try { // AvailableCommandsSerializer_v291 complains otherwise ByteBuf.class.getMethod("writeShortLE", int.class); @@ -144,24 +176,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } } - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { - geyserConfig.getRemote().setAddress(Bukkit.getIp()); - } - geyserConfig.getRemote().setPort(Bukkit.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(Bukkit.getPort()); - } - - this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) - : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - // Remove this in like a year if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION)); @@ -172,7 +186,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); this.getPluginLoader().disablePlugin(this); - return; } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) { // Floodgate installed means that the user wants Floodgate authentication geyserLogger.debug("Auto-setting to Floodgate authentication."); @@ -181,11 +194,43 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.loadFloodgate(this); + // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes + Bukkit.getPluginManager().registerEvents(new Listener() { + + @EventHandler + public void onServerLoaded(ServerLoadEvent event) { + // Wait until all plugins have loaded so Geyser can start + postStartup(); + } + }, this); + + // Because Bukkit locks its command map upon startup, we need to + // add our plugin commands in onEnable, but populating the executor + // can happen at any time + CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); + for (Extension extension : this.geyser.extensionManager().extensions()) { + + // Thanks again, Bukkit + try { + Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + constructor.setAccessible(true); + + PluginCommand pluginCommand = constructor.newInstance(extension.description().id(), this); + pluginCommand.setDescription("The main command for the " + extension.name() + " Geyser extension!"); + + commandMap.register(extension.description().id(), "geyserext", pluginCommand); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { + this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex); + } + } + } + + private void postStartup() { + GeyserImpl.start(); + // Turn "(MC: 1.16.4)" into 1.16.4. this.minecraftVersion = Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0]; - this.geyser = GeyserImpl.start(PlatformType.SPIGOT, this); - if (geyserConfig.isLegacyPingPassthrough()) { this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); } else { @@ -275,25 +320,18 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { PluginCommand geyserCommand = this.getCommand("geyser"); geyserCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands())); - CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { Map commands = entry.getValue(); if (commands.isEmpty()) { continue; } - // Thanks again, Bukkit - try { - Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); - constructor.setAccessible(true); - - PluginCommand pluginCommand = constructor.newInstance(entry.getKey().description().id(), this); - pluginCommand.setExecutor(new GeyserSpigotCommandExecutor(this.geyser, commands)); - pluginCommand.setDescription("The main command for the " + entry.getKey().name() + " Geyser extension!"); - commandMap.register(entry.getKey().description().id(), "geyserext", pluginCommand); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { - this.geyserLogger.error("Failed to construct PluginCommand for extension " + entry.getKey().description().name(), ex); + PluginCommand command = this.getCommand(entry.getKey().description().id()); + if (command == null) { + continue; } + + command.setExecutor(new GeyserSpigotCommandExecutor(this.geyser, commands)); } if (!INITIALIZED) { diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index d912d28d8..42040f6ab 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -72,8 +72,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { private GeyserImpl geyser; - @Override - public void onEnable() { + public void onLoad() { GeyserLocale.init(this); if (!configDir.exists()) @@ -114,7 +113,13 @@ public class GeyserSpongePlugin implements GeyserBootstrap { this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - this.geyser = GeyserImpl.start(PlatformType.SPONGE, this); + + this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); + } + + @Override + public void onEnable() { + GeyserImpl.start(); if (geyserConfig.isLegacyPingPassthrough()) { this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(geyser); @@ -124,6 +129,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser); this.geyserCommandManager.init(); + Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { @@ -166,6 +172,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap { return configDir.toPath(); } + @Listener + public void onServerStarting() { + onLoad(); + } + @Listener public void onServerStart(GameStartedServerEvent event) { onEnable(); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 052a41439..80d17f6a7 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -217,7 +217,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { // Allow libraries like Protocol to have their debug information passthrough logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO); - geyser = GeyserImpl.start(PlatformType.STANDALONE, this); + geyser = GeyserImpl.load(PlatformType.STANDALONE, this); + GeyserImpl.start(); + geyserCommandManager = new GeyserStandaloneCommandManager(geyser); geyserCommandManager.init(); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 30d8deccd..dc31b3fdd 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -88,15 +88,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Override public void onEnable() { - try { - Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class); - } catch (NoSuchMethodException e) { - // velocitypowered.com has a build that is very outdated - logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " + - "that has likely been downloaded is very outdated and does not support 1.19."); - return; - } - GeyserLocale.init(this); try { @@ -131,6 +122,17 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); + + try { + Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class); + } catch (NoSuchMethodException e) { + // velocitypowered.com has a build that is very outdated + logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " + + "that has likely been downloaded is very outdated and does not support 1.19."); + return; + } + // Remove this in like a year try { // Should only exist on 1.0 @@ -153,7 +155,10 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile()); - this.geyser = GeyserImpl.start(PlatformType.VELOCITY, this); + } + + private void postStartup() { + GeyserImpl.start(); this.geyserInjector = new GeyserVelocityInjector(proxyServer); // Will be initialized after the proxy has been bound @@ -222,9 +227,14 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Subscribe public void onProxyBound(ListenerBoundEvent event) { - if (event.getListenerType() == ListenerType.MINECRAFT && geyserInjector != null) { - // After this bound, we know that the channel initializer cannot change without it being ineffective for Velocity, too - geyserInjector.initializeLocalChannel(this); + if (event.getListenerType() == ListenerType.MINECRAFT) { + // Once listener is bound, do our startup process + this.postStartup(); + + if (geyserInjector != null) { + // After this bound, we know that the channel initializer cannot change without it being ineffective for Velocity, too + geyserInjector.initializeLocalChannel(this); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 24a5f5d2c..115a7245e 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -57,6 +57,7 @@ import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.news.NewsItemAction; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; @@ -143,8 +144,8 @@ public class GeyserImpl implements GeyserApi { private final PlatformType platformType; private final GeyserBootstrap bootstrap; - private final EventBus eventBus; - private final GeyserExtensionManager extensionManager; + private final EventBus eventBus; + private GeyserExtensionManager extensionManager; private Metrics metrics; @@ -162,9 +163,19 @@ public class GeyserImpl implements GeyserApi { this.platformType = platformType; this.bootstrap = bootstrap; + GeyserLocale.finalizeDefaultLocale(this); + + /* Initialize event bus */ + this.eventBus = new GeyserEventBus(); + + /* Load Extensions */ + this.extensionManager = new GeyserExtensionManager(); + this.extensionManager.init(); + } + + public void initialize() { long startupTime = System.currentTimeMillis(); - GeyserLocale.finalizeDefaultLocale(this); GeyserLogger logger = bootstrap.getGeyserLogger(); logger.info("******************************************"); @@ -173,13 +184,8 @@ public class GeyserImpl implements GeyserApi { logger.info(""); logger.info("******************************************"); - /* Initialize event bus */ - this.eventBus = new GeyserEventBus(); - - /* Load Extensions */ - this.extensionManager = new GeyserExtensionManager(); - this.extensionManager.init(); + /* Enable extensions */ this.extensionManager.enableExtensions(); this.eventBus.fire(new GeyserPreInitializeEvent(this.extensionManager, this.eventBus)); @@ -193,7 +199,7 @@ public class GeyserImpl implements GeyserApi { MessageTranslator.init(); MinecraftLocale.init(); - start(); + startInstance(); GeyserConfiguration config = bootstrap.getGeyserConfig(); @@ -225,7 +231,7 @@ public class GeyserImpl implements GeyserApi { } } - private void start() { + private void startInstance() { this.scheduledThread = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("Geyser Scheduled Thread")); GeyserLogger logger = bootstrap.getGeyserLogger(); @@ -589,7 +595,7 @@ public class GeyserImpl implements GeyserApi { @Override @NonNull - public EventBus eventBus() { + public EventBus eventBus() { return this.eventBus; } @@ -612,18 +618,26 @@ public class GeyserImpl implements GeyserApi { return Integer.parseInt(BUILD_NUMBER); } - public static GeyserImpl start(PlatformType platformType, GeyserBootstrap bootstrap) { + public static GeyserImpl load(PlatformType platformType, GeyserBootstrap bootstrap) { if (instance == null) { return new GeyserImpl(platformType, bootstrap); } + return instance; + } + + public static void start() { + if (instance == null) { + throw new RuntimeException("Geyser has not been loaded yet!"); + } + // We've been reloaded if (instance.isShuttingDown()) { instance.shuttingDown = false; - instance.start(); + instance.startInstance(); + } else { + instance.initialize(); } - - return instance; } public GeyserLogger getLogger() { diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java index f634931f4..9593e327e 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventBus.java @@ -32,6 +32,7 @@ import org.geysermc.event.bus.impl.OwnedEventBusImpl; import org.geysermc.event.subscribe.OwnedSubscriber; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.EventSubscriber; import org.geysermc.geyser.api.extension.Extension; @@ -40,11 +41,11 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; @SuppressWarnings("unchecked") -public final class GeyserEventBus extends OwnedEventBusImpl> - implements EventBus { +public final class GeyserEventBus extends OwnedEventBusImpl> + implements EventBus { @Override - protected > B makeSubscription( - @NonNull Extension owner, + protected > B makeSubscription( + @NonNull EventRegistrar owner, @NonNull Class eventClass, @NonNull Subscribe subscribe, @NonNull L listener, @@ -55,8 +56,8 @@ public final class GeyserEventBus extends OwnedEventBusImpl> B makeSubscription( - @NonNull Extension owner, + protected > B makeSubscription( + @NonNull EventRegistrar owner, @NonNull Class eventClass, @NonNull Consumer handler, @NonNull PostOrder postOrder) { @@ -65,7 +66,7 @@ public final class GeyserEventBus extends OwnedEventBusImpl Set> subscribers(@NonNull Class eventClass) { + public Set> subscribers(@NonNull Class eventClass) { return castGenericSet(super.subscribers(eventClass)); } } diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventRegistrar.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventRegistrar.java new file mode 100644 index 000000000..85c36a132 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventRegistrar.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.event; + +import org.geysermc.geyser.api.event.EventRegistrar; + +public record GeyserEventRegistrar(Object owner) implements EventRegistrar { + + @Override + public String toString() { + return "GeyserEventRegistrar{" + + "owner=" + this.owner + + '}'; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java index 5012037bb..d33de8cdd 100644 --- a/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java +++ b/core/src/main/java/org/geysermc/geyser/event/GeyserEventSubscriber.java @@ -29,16 +29,17 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.impl.OwnedSubscriberImpl; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.ExtensionEventSubscriber; import org.geysermc.geyser.api.extension.Extension; import java.util.function.BiConsumer; import java.util.function.Consumer; -public final class GeyserEventSubscriber extends OwnedSubscriberImpl +public final class GeyserEventSubscriber extends OwnedSubscriberImpl implements ExtensionEventSubscriber { GeyserEventSubscriber( - @NonNull Extension owner, + @NonNull R owner, @NonNull Class eventClass, @NonNull Consumer handler, @NonNull PostOrder postOrder) { @@ -46,7 +47,7 @@ public final class GeyserEventSubscriber extends OwnedSubscribe } GeyserEventSubscriber( - @NonNull Extension owner, + @NonNull R owner, @NonNull Class eventClass, @NonNull PostOrder postOrder, boolean ignoreCancelled, diff --git a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java index 7294d4345..f56b254a6 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java +++ b/core/src/main/java/org/geysermc/geyser/extension/event/GeyserExtensionEventBus.java @@ -30,6 +30,7 @@ import org.geysermc.event.Event; import org.geysermc.event.PostOrder; import org.geysermc.event.subscribe.Subscriber; import org.geysermc.geyser.api.event.EventBus; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.EventSubscriber; import org.geysermc.geyser.api.event.ExtensionEventBus; import org.geysermc.geyser.api.extension.Extension; @@ -37,10 +38,12 @@ import org.geysermc.geyser.api.extension.Extension; import java.util.Set; import java.util.function.Consumer; -public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) implements ExtensionEventBus { +public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) implements ExtensionEventBus { + + @SuppressWarnings({"rawtypes", "unchecked"}) @Override - public void unsubscribe(@NonNull EventSubscriber subscription) { - eventBus.unsubscribe(subscription); + public void unsubscribe(@NonNull EventSubscriber subscription) { + eventBus.unsubscribe((EventSubscriber) subscription); } @Override @@ -49,7 +52,7 @@ public record GeyserExtensionEventBus(EventBus eventBus, Extension extension) im } @Override - public @NonNull Set> subscribers(@NonNull Class eventClass) { + public @NonNull Set> subscribers(@NonNull Class eventClass) { return eventBus.subscribers(eventClass); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java index e7837688c..99a9213fe 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java @@ -26,11 +26,13 @@ package org.geysermc.geyser.registry.loader; import org.geysermc.geyser.api.command.Command; +import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.event.GeyserEventRegistrar; import org.geysermc.geyser.item.GeyserCustomItemData; import org.geysermc.geyser.item.GeyserCustomItemOptions; import org.geysermc.geyser.item.GeyserNonVanillaCustomItemData; @@ -49,6 +51,7 @@ public class ProviderRegistryLoader implements RegistryLoader, Prov providers.put(CustomItemData.Builder.class, args -> new GeyserCustomItemData.CustomItemDataBuilder()); providers.put(CustomItemOptions.Builder.class, args -> new GeyserCustomItemOptions.CustomItemOptionsBuilder()); providers.put(NonVanillaCustomItemData.Builder.class, args -> new GeyserNonVanillaCustomItemData.NonVanillaCustomItemDataBuilder()); + providers.put(EventRegistrar.class, args -> new GeyserEventRegistrar(args[0])); return providers; } From 896bf7c218919f42c1096fcb695dd7dc6d4facbf Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 4 Sep 2022 16:19:56 -0500 Subject: [PATCH 161/290] Fix bungeecord startup and move version checks to onLoad --- .../bungeecord/GeyserBungeePlugin.java | 80 +++++++++--------- .../platform/spigot/GeyserSpigotPlugin.java | 82 +++++++++---------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index eb2a3b9c4..13604a3d4 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -72,6 +72,20 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { @Override public void onLoad() { + // Copied from ViaVersion. + // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 + try { + ProtocolConstants.class.getField("MINECRAFT_1_19_1"); + } catch (NoSuchFieldException e) { + getLogger().warning(" / \\"); + getLogger().warning(" / \\"); + getLogger().warning(" / | \\"); + getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); + getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); + getLogger().warning(" / o \\"); + getLogger().warning("/_____________\\"); + } + GeyserLocale.init(this); if (!getDataFolder().exists()) @@ -89,6 +103,31 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { return; } + this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + + this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); + } + + @Override + public void onEnable() { + // Remove this in like a year + if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { + geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/")); + return; + } + + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { + geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + return; + } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { + // Floodgate installed means that the user wants Floodgate authentication + geyserLogger.debug("Auto-setting to Floodgate authentication."); + geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); + } + + geyserConfig.loadFloodgate(this); + if (getProxy().getConfig().getListeners().size() == 1) { ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0]; @@ -109,45 +148,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } } - this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - - this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); - } - - @Override - public void onEnable() { - // Copied from ViaVersion. - // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 - try { - ProtocolConstants.class.getField("MINECRAFT_1_19_1"); - } catch (NoSuchFieldException e) { - getLogger().warning(" / \\"); - getLogger().warning(" / \\"); - getLogger().warning(" / | \\"); - getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); - getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); - getLogger().warning(" / o \\"); - getLogger().warning("/_____________\\"); - } - - // Remove this in like a year - if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/")); - return; - } - - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); - } - - geyserConfig.loadFloodgate(this); - // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating // task that waits for a field to be filled which is set after the plugin enable // process is complete @@ -171,7 +171,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { listenersField.setAccessible(true); Collection listeners = (Collection) listenersField.get(BungeeCord.getInstance()); - if (!listeners.isEmpty()) { + if (listeners.isEmpty()) { this.getProxy().getScheduler().schedule(this, this::postStartup, tries, TimeUnit.SECONDS); } else { this.awaitStartupCompletion(++tries); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 2000dc114..4407af6c7 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -104,47 +104,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onLoad() { - GeyserLocale.init(this); - - // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed - try { - if (!getDataFolder().exists()) { - getDataFolder().mkdir(); - } - File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", - (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class); - } catch (IOException ex) { - getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); - ex.printStackTrace(); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { - geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { - geyserConfig.getRemote().setAddress(Bukkit.getIp()); - } - geyserConfig.getRemote().setPort(Bukkit.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(Bukkit.getPort()); - } - - this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) - : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); - - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - - this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this); - } - - @Override - public void onEnable() { try { // AvailableCommandsSerializer_v291 complains otherwise ByteBuf.class.getMethod("writeShortLE", int.class); @@ -176,6 +135,33 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } } + GeyserLocale.init(this); + + // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed + try { + if (!getDataFolder().exists()) { + getDataFolder().mkdir(); + } + File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", + (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); + this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class); + } catch (IOException ex) { + getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); + ex.printStackTrace(); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) + : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); + + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + + this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this); + } + + @Override + public void onEnable() { // Remove this in like a year if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION)); @@ -192,6 +178,20 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); } + // By default this should be localhost but may need to be changed in some circumstances + if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { + geyserConfig.setAutoconfiguredRemote(true); + // Don't use localhost if not listening on all interfaces + if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { + geyserConfig.getRemote().setAddress(Bukkit.getIp()); + } + geyserConfig.getRemote().setPort(Bukkit.getPort()); + } + + if (geyserConfig.getBedrock().isCloneRemotePort()) { + geyserConfig.getBedrock().setPort(Bukkit.getPort()); + } + geyserConfig.loadFloodgate(this); // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes From 770dfca32889b7d8e9c4fbc511966b3f0020a65f Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 4 Sep 2022 16:35:50 -0500 Subject: [PATCH 162/290] Fix dumps --- .../java/org/geysermc/geyser/dump/DumpInfo.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index da52d064c..4c2d24dd4 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -70,7 +70,7 @@ public class DumpInfo { private final String cpuName; private final Locale systemLocale; private final String systemEncoding; - private Properties gitInfo; + private final GitInfo gitInfo; private final GeyserConfiguration config; private final Floodgate floodgate; private final Object2IntMap userPlatforms; @@ -89,11 +89,7 @@ public class DumpInfo { this.systemLocale = Locale.getDefault(); this.systemEncoding = System.getProperty("file.encoding"); - try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("git.properties")) { - this.gitInfo = new Properties(); - this.gitInfo.load(stream); - } catch (IOException ignored) { - } + this.gitInfo = new GitInfo(GeyserImpl.VERSION, GeyserImpl.BUILD_NUMBER, GeyserImpl.GIT_VERSION, GeyserImpl.BRANCH); this.config = GeyserImpl.getInstance().getConfig(); this.floodgate = new Floodgate(); @@ -300,4 +296,13 @@ public class DumpInfo { public String main; public List authors; } + + @Getter + @AllArgsConstructor + public static class GitInfo { + private final String version; + private final String buildNumber; + private final String commitHash; + private final String branchName; + } } From 25f43f3152a2166abbb64936616299d9f0c9e3ed Mon Sep 17 00:00:00 2001 From: Typical <53472591+TypicalShavonne@users.noreply.github.com> Date: Mon, 5 Sep 2022 10:35:47 +0700 Subject: [PATCH 163/290] Updating README (#3268) --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 464e67d76..d02d50d2b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge ## What's Left to be Added/Fixed - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) -- Resource pack conversion/CustomModelData - Some Entity Flags - Structure block UI @@ -43,9 +42,8 @@ There are a few things Geyser is unable to support due to various differences be ## Compiling 1. Clone the repo to your computer -2. [Install Maven](https://maven.apache.org/install.html) -3. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This command downloads all the needed submodules for Geyser and is a crucial step in this process. -4. Run `mvn clean install` and locate to the `target` folder. +2. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This command downloads all the needed submodules for Geyser and is a crucial step in this process. +3. Run `gradlew build` and locate to `bootstrap/build` folder. ## Contributing Any contributions are appreciated. Please feel free to reach out to us on [Discord](http://discord.geysermc.org/) if 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 164/290] 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 2d7a463089698a8ed33d4261bf64ae3e1a892ee5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 11 Sep 2022 19:26:22 -0400 Subject: [PATCH 165/290] Make Geyser dumps backwards compatible --- core/build.gradle.kts | 6 +++++- .../src/main/java/org/geysermc/geyser/GeyserImpl.java | 2 ++ .../main/java/org/geysermc/geyser/dump/DumpInfo.java | 11 ++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 83591e7ad..41cf83538 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -80,12 +80,16 @@ configure { val indra = the() val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" - val gitVersion = "git-${branchName()}-${indra.commit()?.name?.substring(0, 7) ?: "0000000"}" + val commit = indra.commit() + val git = indra.git() + val gitVersion = "git-${branchName()}-${commit?.name?.substring(0, 7) ?: "0000000"}" replaceToken("\${version}", "${project.version} ($gitVersion)", mainFile) replaceToken("\${gitVersion}", gitVersion, mainFile) replaceToken("\${buildNumber}", buildNumber(), mainFile) replaceToken("\${branch}", branchName(), mainFile) + if (commit != null && commit.name != null) replaceToken("\${commit}", commit.name, mainFile) + if (git != null) replaceToken("\${repository}", git.repository.config.getString("remote", "origin", "url")) } fun Project.branchName(): String = diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 115a7245e..ce2474d50 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -116,6 +116,8 @@ public class GeyserImpl implements GeyserApi { public static final String BUILD_NUMBER = "${buildNumber}"; public static final String BRANCH = "${branch}"; + public static final String COMMIT = "${commit}"; + public static final String REPOSITORY = "${repository}"; /** * Oauth client ID for Microsoft authentication diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 4c2d24dd4..5197f2107 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.dump; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; @@ -50,7 +51,6 @@ import org.geysermc.geyser.util.WebUtils; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -89,7 +89,7 @@ public class DumpInfo { this.systemLocale = Locale.getDefault(); this.systemEncoding = System.getProperty("file.encoding"); - this.gitInfo = new GitInfo(GeyserImpl.VERSION, GeyserImpl.BUILD_NUMBER, GeyserImpl.GIT_VERSION, GeyserImpl.BRANCH); + this.gitInfo = new GitInfo(GeyserImpl.BUILD_NUMBER, GeyserImpl.COMMIT.substring(0, 7), GeyserImpl.COMMIT, GeyserImpl.BRANCH, GeyserImpl.REPOSITORY); this.config = GeyserImpl.getInstance().getConfig(); this.floodgate = new Floodgate(); @@ -300,9 +300,14 @@ public class DumpInfo { @Getter @AllArgsConstructor public static class GitInfo { - private final String version; private final String buildNumber; + @JsonProperty("git.commit.id.abbrev") + private final String commitHashAbbrev; + @JsonProperty("git.commit.id") private final String commitHash; + @JsonProperty("git.branch") private final String branchName; + @JsonProperty("git.remote.origin.url") + private final String originUrl; } } From a99afe44183b89b54b67993ffe0c23150a649d62 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 13 Sep 2022 16:24:08 -0400 Subject: [PATCH 166/290] Remove usage of Fastutil Object2Reference maps These are only beneficial for containsValue checks. --- core/build.gradle.kts | 1 - .../geyser/extension/GeyserExtensionClassLoader.java | 6 +++--- .../geysermc/geyser/extension/GeyserExtensionLoader.java | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 41cf83538..5049c93ab 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,7 +26,6 @@ dependencies { implementation("com.nukkitx.fastutil", "fastutil-int-boolean-maps", Versions.fastutilVersion) implementation("com.nukkitx.fastutil", "fastutil-object-int-maps", Versions.fastutilVersion) implementation("com.nukkitx.fastutil", "fastutil-object-object-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-object-reference-maps", Versions.fastutilVersion) // Network libraries implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index b220ab576..b94e70ed0 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.extension; -import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; @@ -39,7 +39,7 @@ import java.nio.file.Path; public class GeyserExtensionClassLoader extends URLClassLoader { private final GeyserExtensionLoader loader; - private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); + private final Object2ObjectMap> classes = new Object2ObjectOpenHashMap<>(); public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException { super(new URL[] { path.toUri().toURL() }, parent); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 44558e798..7e998e413 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.extension; -import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.Geyser; @@ -51,7 +51,7 @@ import java.util.stream.Stream; public class GeyserExtensionLoader extends ExtensionLoader { private static final Pattern[] EXTENSION_FILTERS = new Pattern[] { Pattern.compile("^.+\\.jar$") }; - private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); + private final Object2ObjectMap> classes = new Object2ObjectOpenHashMap<>(); private final Map classLoaders = new HashMap<>(); private final Map extensionContainers = new HashMap<>(); private final Path extensionsDirectory = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("extensions"); From 6df8740955f0060821e7e2c7b7fbcb0a25496cbc Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 14 Sep 2022 14:19:56 -0400 Subject: [PATCH 167/290] Only register commands on Spigot if the extension has commands --- .../geyser/api/extension/Extension.java | 2 +- .../geyser/api/extension/ExtensionLoader.java | 3 +- .../api/extension/ExtensionManager.java | 36 ++------------- .../platform/spigot/GeyserSpigotPlugin.java | 16 +++---- .../java/org/geysermc/geyser/GeyserImpl.java | 8 +--- .../geyser/command/GeyserCommand.java | 3 +- .../extension/GeyserExtensionManager.java | 45 +++---------------- 7 files changed, 21 insertions(+), 92 deletions(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java index 8d4e4da64..33fc159de 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java @@ -124,7 +124,7 @@ public interface Extension extends EventRegistrar { */ @NonNull default ExtensionLoader extensionLoader() { - return Objects.requireNonNull(this.extensionManager().extensionLoader(this)); + return Objects.requireNonNull(this.extensionManager().extensionLoader()); } /** diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java index c84c37919..30414d500 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -34,7 +34,6 @@ import java.nio.file.Path; * The extension loader is responsible for loading, unloading, enabling and disabling extensions */ public abstract class ExtensionLoader { - /** * Gets if the given {@link Extension} is enabled. * @@ -101,6 +100,6 @@ public abstract class ExtensionLoader { * @param extensionManager the extension manager */ protected void register(@NonNull Extension extension, @NonNull ExtensionManager extensionManager) { - extensionManager.register(extension, this); + extensionManager.register(extension); } } \ No newline at end of file diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java index 65d6c66da..a9d0d7376 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java @@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collection; -import java.util.Map; /** * Manages Geyser {@link Extension}s @@ -59,15 +58,6 @@ public abstract class ExtensionManager { */ public abstract void disable(@NonNull Extension extension); - /** - * Gets the {@link ExtensionLoader} responsible for loading - * the given {@link Extension}. - * - * @return the extension loader for loading the given extension - */ - @Nullable - public abstract ExtensionLoader extensionLoader(@NonNull Extension extension); - /** * Gets all the {@link Extension}s currently loaded. * @@ -77,37 +67,19 @@ public abstract class ExtensionManager { public abstract Collection extensions(); /** - * Gets the {@link ExtensionLoader} with the given identifier. + * Gets the {@link ExtensionLoader}. * - * @param identifier the identifier - * @return the extension loader at the given identifier + * @return the extension loader */ @Nullable - public abstract ExtensionLoader extensionLoader(@NonNull String identifier); - - /** - * Registers an {@link ExtensionLoader} with the given identifier. - * - * @param identifier the identifier - * @param extensionLoader the extension loader - */ - public abstract void registerExtensionLoader(@NonNull String identifier, @NonNull ExtensionLoader extensionLoader); - - /** - * Gets all the currently registered {@link ExtensionLoader}s. - * - * @return all the currently registered extension loaders - */ - @NonNull - public abstract Map extensionLoaders(); + public abstract ExtensionLoader extensionLoader(); /** * Registers an {@link Extension} with the given {@link ExtensionLoader}. * * @param extension the extension - * @param loader the loader */ - public abstract void register(@NonNull Extension extension, @NonNull ExtensionLoader loader); + public abstract void register(@NonNull Extension extension); /** * Loads all extensions from the given {@link ExtensionLoader}. diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 4407af6c7..60b1cfa21 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -62,12 +62,7 @@ import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigot1_12NativeWorldManager; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigot1_12WorldManager; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotFallbackWorldManager; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotLegacyNativeWorldManager; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorldManager; -import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.*; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -204,12 +199,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } }, this); + this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); + this.geyserCommandManager.init(); + // Because Bukkit locks its command map upon startup, we need to // add our plugin commands in onEnable, but populating the executor // can happen at any time CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); - for (Extension extension : this.geyser.extensionManager().extensions()) { - + for (Extension extension : this.geyserCommandManager.extensionCommands().keySet()) { // Thanks again, Bukkit try { Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); @@ -245,9 +242,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); - this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); - this.geyserCommandManager.init(); - boolean isViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; if (isViaVersion) { try { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index ce2474d50..a10e54f90 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -147,7 +147,7 @@ public class GeyserImpl implements GeyserApi { private final GeyserBootstrap bootstrap; private final EventBus eventBus; - private GeyserExtensionManager extensionManager; + private final GeyserExtensionManager extensionManager; private Metrics metrics; @@ -173,6 +173,7 @@ public class GeyserImpl implements GeyserApi { /* Load Extensions */ this.extensionManager = new GeyserExtensionManager(); this.extensionManager.init(); + this.eventBus.fire(new GeyserPreInitializeEvent(this.extensionManager, this.eventBus)); } public void initialize() { @@ -186,11 +187,6 @@ public class GeyserImpl implements GeyserApi { logger.info(""); logger.info("******************************************"); - - /* Enable extensions */ - this.extensionManager.enableExtensions(); - this.eventBus.fire(new GeyserPreInitializeEvent(this.extensionManager, this.eventBus)); - /* Initialize registries */ Registries.init(); BlockRegistries.init(); diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java index 0d020ad08..5808dbc2c 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java @@ -33,7 +33,6 @@ import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.session.GeyserSession; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -49,7 +48,7 @@ public abstract class GeyserCommand implements Command { protected final String description; protected final String permission; - private List aliases = new ArrayList<>(); + private List aliases = Collections.emptyList(); public abstract void execute(@Nullable GeyserSession session, GeyserCommandSource sender, String[] args); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index 7d80c2cf6..5dd924301 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.extension; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; @@ -39,34 +37,23 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import java.util.stream.Collectors; public class GeyserExtensionManager extends ExtensionManager { - private static final Key BASE_EXTENSION_LOADER_KEY = Key.key("geysermc", "base"); - - private final Map extensionLoaderTypes = new Object2ObjectOpenHashMap<>(); - + private final GeyserExtensionLoader extensionLoader = new GeyserExtensionLoader(); private final Map extensions = new LinkedHashMap<>(); - private final Map extensionsLoaders = new LinkedHashMap<>(); public void init() { GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.load.loading")); - extensionLoaderTypes.put(BASE_EXTENSION_LOADER_KEY, new GeyserExtensionLoader()); - for (ExtensionLoader loader : this.extensionLoaders().values()) { - this.loadAllExtensions(loader); - } + loadAllExtensions(this.extensionLoader); + enableExtensions(); GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.load.done", this.extensions.size())); } @Override public Extension extension(@NonNull String name) { - if (this.extensions.containsKey(name)) { - return this.extensions.get(name); - } - - return null; + return this.extensions.get(name); } @Override @@ -121,37 +108,19 @@ public class GeyserExtensionManager extends ExtensionManager { } } - @Override - public ExtensionLoader extensionLoader(@NonNull Extension extension) { - return this.extensionsLoaders.get(extension); - } - @NonNull @Override public Collection extensions() { return Collections.unmodifiableCollection(this.extensions.values()); } - @Nullable @Override - public ExtensionLoader extensionLoader(@NonNull String identifier) { - return this.extensionLoaderTypes.get(Key.key(identifier)); + public @Nullable ExtensionLoader extensionLoader() { + return this.extensionLoader; } @Override - public void registerExtensionLoader(@NonNull String identifier, @NonNull ExtensionLoader extensionLoader) { - this.extensionLoaderTypes.put(Key.key(identifier), extensionLoader); - } - - @NonNull - @Override - public Map extensionLoaders() { - return this.extensionLoaderTypes.entrySet().stream().collect(Collectors.toMap(key -> key.getKey().asString(), Map.Entry::getValue)); - } - - @Override - public void register(@NonNull Extension extension, @NonNull ExtensionLoader loader) { - this.extensionsLoaders.put(extension, loader); + public void register(@NonNull Extension extension) { this.extensions.put(extension.name(), extension); } } From 77827d5cf5b81457f912570d1c4673e83c872813 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 14 Sep 2022 18:09:08 -0400 Subject: [PATCH 168/290] Return to using snapshot pinned Network version --- build-logic/src/main/kotlin/Versions.kt | 4 +--- settings.gradle.kts | 12 +----------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 44996cd3d..2dac0f4c6 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -32,9 +32,7 @@ object Versions { const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" const val protocolVersion = "0bd459f" - // Not pinned to specific version due to possible gradle bug - // See comment in settings.gradle.kts - const val raknetVersion = "1.6.28-SNAPSHOT" + const val raknetVersion = "1.6.28-20220125.214016-6" const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" const val packetlibVersion = "3.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index dd08f3922..3aa66d493 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,17 +4,7 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { // Floodgate, Cumulus etc. - maven("https://repo.opencollab.dev/maven-releases") { - mavenContent { releasesOnly() } - } - maven("https://repo.opencollab.dev/maven-snapshots") { - mavenContent { - // This has the unintended side effect of not allowing snapshot version pinning. - // Likely a bug in Gradle's implementation of snapshot pinning - // See https://github.com/gradle/gradle/pull/406 - snapshotsOnly() - } - } + maven("https://repo.opencollab.dev/main") // Paper, Velocity maven("https://repo.papermc.io/repository/maven-public") From e64e12ff98886a338a3beee76f49a86010cc388f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 14 Sep 2022 21:17:08 -0400 Subject: [PATCH 169/290] Initial support for 1.19.30 Bedrock --- build-logic/src/main/kotlin/Versions.kt | 2 +- core/build.gradle.kts | 2 +- .../network/ConnectorServerEventHandler.java | 3 +- .../geysermc/geyser/network/GameProtocol.java | 2 + .../geyser/network/LoggingPacketHandler.java | 7 +++ .../geyser/network/UpstreamPacketHandler.java | 15 +++++ .../populator/RecipeRegistryPopulator.java | 7 ++- .../geyser/session/SessionManager.java | 3 +- .../java/JavaUpdateRecipesTranslator.java | 63 +++++++++---------- .../JavaContainerSetSlotTranslator.java | 3 +- 10 files changed, 66 insertions(+), 41 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 2dac0f4c6..8d0185cc8 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -31,7 +31,7 @@ object Versions { const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" - const val protocolVersion = "0bd459f" + const val protocolVersion = "f0feacd" const val raknetVersion = "1.6.28-20220125.214016-6" const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 5049c93ab..b0325e33c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // Network libraries implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) - api("com.github.CloudburstMC.Protocol", "bedrock-v544", Versions.protocolVersion) { + api("com.github.CloudburstMC.Protocol", "bedrock-v553", Versions.protocolVersion) { exclude("com.nukkitx.network", "raknet") exclude("com.nukkitx", "nbt") } diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index 4ed077a7b..bf655740f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.network; import com.nukkitx.protocol.bedrock.BedrockPong; import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; import com.nukkitx.protocol.bedrock.BedrockServerSession; +import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultEventLoopGroup; @@ -171,7 +172,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public void onSessionCreation(@Nonnull BedrockServerSession bedrockServerSession) { try { - bedrockServerSession.setPacketCodec(GameProtocol.DEFAULT_BEDROCK_CODEC); + bedrockServerSession.setPacketCodec(Bedrock_v553.V553_CODEC); // Has the RequestNetworkSettingsPacket bedrockServerSession.setLogging(true); bedrockServerSession.setCompressionLevel(geyser.getConfig().getBedrock().getCompressionLevel()); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(geyser, new GeyserSession(geyser, bedrockServerSession, eventLoopGroup.next()))); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 006f40ace..dde0b0c04 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; +import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -71,6 +72,7 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v553.V553_CODEC); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index b0b707ee0..7edf560e8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -856,4 +856,11 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public boolean handle(FilterTextPacket packet) { return defaultHandler(packet); } + + // 1.19.30 new packet + + @Override + public boolean handle(RequestNetworkSettingsPacket packet) { + return defaultHandler(packet); + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 5a8fa3013..286a2eb9b 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.network; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.data.ExperimentData; +import com.nukkitx.protocol.bedrock.data.PacketCompressionAlgorithm; import com.nukkitx.protocol.bedrock.data.ResourcePackType; import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.GeyserImpl; @@ -61,6 +62,20 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return translateAndDefault(packet); } + @Override + public boolean handle(RequestNetworkSettingsPacket packet) { + // New since 1.19.30 - sent before login packet + PacketCompressionAlgorithm algorithm = PacketCompressionAlgorithm.ZLIB; + + NetworkSettingsPacket responsePacket = new NetworkSettingsPacket(); + responsePacket.setCompressionAlgorithm(algorithm); + responsePacket.setCompressionThreshold(512); + session.sendUpstreamPacketImmediately(responsePacket); + + session.getUpstream().getSession().setCompression(algorithm); + return true; + } + @Override public boolean handle(LoginPacket loginPacket) { if (geyser.isShuttingDown()) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index f0a215f2a..920ada5fb 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -33,6 +33,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -171,7 +172,7 @@ public class RecipeRegistryPopulator { /* Convert end */ return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } List inputs = new ObjectArrayList<>(); for (JsonNode entry : node.get("inputs")) { @@ -191,10 +192,10 @@ public class RecipeRegistryPopulator { if (type == 5) { // Shulker box return CraftingData.fromShulkerBox(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } return CraftingData.fromShapeless(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) { diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 2660f54b1..02940e00c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -62,7 +62,8 @@ public final class SessionManager { } public void removeSession(GeyserSession session) { - if (sessions.remove(session.getPlayerEntity().getUuid()) == null) { + UUID uuid = session.getPlayerEntity().getUuid(); + if (uuid == null || sessions.remove(uuid) == null) { // Connection was likely pending pendingSessions.remove(session); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 4c72a359a..d11caf601 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -34,9 +34,10 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeDa import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -99,8 +100,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); + private ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) { + Map, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { - squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new IntOpenHashSet()).add(i); + squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i); continue; } Ingredient ingredient = ingredients[i]; - Map> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(item -> ItemTranslator.translateToBedrock(session, item)) - .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); - Set optionSet = new HashSet<>(groupedByIds.size()); - for (Map.Entry> entry : groupedByIds.entrySet()) { + Map> groupedByIds = Arrays.stream(ingredient.getOptions()) + .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item))) + .collect(Collectors.groupingBy(item -> new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount()))); + Set optionSet = new HashSet<>(groupedByIds.size()); + for (Map.Entry> entry : groupedByIds.entrySet()) { if (entry.getValue().size() > 1) { GroupedItem groupedItem = entry.getKey(); int idCount = 0; @@ -234,42 +236,38 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new IntOpenHashSet()).add(i); } int totalCombinations = 1; - for (Set optionSet : squashedOptions.keySet()) { + for (Set optionSet : squashedOptions.keySet()) { totalCombinations *= optionSet.size(); } if (totalCombinations > 500) { - ItemData[] translatedItems = new ItemData[ingredients.length]; + ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length]; for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length > 0) { - translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]); + translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0])); } else { - translatedItems[i] = ItemData.AIR; + translatedItems[i] = ItemDescriptorWithCount.EMPTY; } } - return new ItemData[][]{translatedItems}; + return new ItemDescriptorWithCount[][]{translatedItems}; } - List> sortedSets = new ArrayList<>(squashedOptions.keySet()); + List> sortedSets = new ArrayList<>(squashedOptions.keySet()); sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder())); - ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length]; + ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length]; int x = 1; - for (Set set : sortedSets) { + for (Set set : sortedSets) { IntSet slotSet = squashedOptions.get(set); int i = 0; - for (ItemData item : set) { + for (ItemDescriptorWithCount item : set) { for (int j = 0; j < totalCombinations / set.size(); j++) { final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x); for (int slot : slotSet) { @@ -288,6 +286,5 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Wed, 14 Sep 2022 21:22:34 -0400 Subject: [PATCH 170/290] Use Indra to get branch name --- core/build.gradle.kts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b0325e33c..f2225dbb8 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -79,20 +79,18 @@ configure { val indra = the() val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" + val branchName = indra.branchName() ?: "DEV" val commit = indra.commit() val git = indra.git() - val gitVersion = "git-${branchName()}-${commit?.name?.substring(0, 7) ?: "0000000"}" + val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" replaceToken("\${version}", "${project.version} ($gitVersion)", mainFile) replaceToken("\${gitVersion}", gitVersion, mainFile) replaceToken("\${buildNumber}", buildNumber(), mainFile) - replaceToken("\${branch}", branchName(), mainFile) + replaceToken("\${branch}", branchName, mainFile) if (commit != null && commit.name != null) replaceToken("\${commit}", commit.name, mainFile) if (git != null) replaceToken("\${repository}", git.repository.config.getString("remote", "origin", "url")) } -fun Project.branchName(): String = - System.getenv("GIT_BRANCH") ?: "local/dev" - fun Project.buildNumber(): Int = Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") \ No newline at end of file From 83be01958f577ddeca9d9934a3deafea9e2bc020 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 15 Sep 2022 15:53:03 -0400 Subject: [PATCH 171/290] Yeet logging into Microsoft with password This has been broken for ages; we need to finally remove it. --- .../geyser/util/LoginEncryptionUtils.java | 41 ++----------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java index c8d6e42d7..8d832f8fa 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -245,13 +245,7 @@ public class LoginEncryptionUtils { } if (response.clickedButtonId() == 1) { - if (isPasswordAuthEnabled) { - session.setMicrosoftAccount(true); - buildAndShowMicrosoftAuthenticationWindow(session); - } else { - // Just show the OAuth code - session.authenticateWithMicrosoftCode(); - } + session.authenticateWithMicrosoftCode(); return; } @@ -315,39 +309,10 @@ public class LoginEncryptionUtils { .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") .input("geyser.auth.login.form.details.pass", "123456", "") .invalidResultHandler(() -> buildAndShowLoginDetailsWindow(session)) - .closedResultHandler(() -> { - if (session.isMicrosoftAccount()) { - buildAndShowMicrosoftAuthenticationWindow(session); - } else { - buildAndShowLoginWindow(session); - } - }) + .closedResultHandler(() -> buildAndShowLoginWindow(session)) .validResultHandler((response) -> session.authenticate(response.next(), response.next()))); } - /** - * Prompts the user between either OAuth code login or manual password authentication - */ - public static void buildAndShowMicrosoftAuthenticationWindow(GeyserSession session) { - session.sendForm( - SimpleForm.builder() - .translator(GeyserLocale::getPlayerLocaleString, session.locale()) - .title("geyser.auth.login.form.notice.btn_login.microsoft") - .button("geyser.auth.login.method.browser") - .button("geyser.auth.login.method.password") - .button("geyser.auth.login.form.notice.btn_disconnect") - .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) - .validResultHandler((response) -> { - if (response.clickedButtonId() == 0) { - session.authenticateWithMicrosoftCode(); - } else if (response.clickedButtonId() == 1) { - buildAndShowLoginDetailsWindow(session); - } else { - session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.locale())); - } - })); - } - /** * Shows the code that a user must input into their browser */ @@ -374,7 +339,7 @@ public class LoginEncryptionUtils { .content(message.toString()) .button1("%gui.done") .button2("%menu.disconnect") - .closedOrInvalidResultHandler(() -> buildAndShowMicrosoftAuthenticationWindow(session)) + .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) .validResultHandler((response) -> { if (response.clickedButtonId() == 1) { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", locale)); From 0aa7411d02380223046a9b55ad38eee8c64b84f6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 15 Sep 2022 20:32:38 -0400 Subject: [PATCH 172/290] Fix git branch on Jenkins (#3286) --- core/build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index f2225dbb8..0d1c16825 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -79,7 +79,8 @@ configure { val indra = the() val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" - val branchName = indra.branchName() ?: "DEV" + // On Jenkins, a detached head is checked out, so indra cannot determine the branch. Fortunately, this environment variable is available. + val branchName = indra.branchName() ?: System.getenv("GIT_BRANCH") ?: "DEV" val commit = indra.commit() val git = indra.git() val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" @@ -93,4 +94,4 @@ configure { } fun Project.buildNumber(): Int = - Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") \ No newline at end of file + Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") From c8a51d783468d18f6d61d8f219277c598020420d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 17 Sep 2022 16:37:30 -0400 Subject: [PATCH 173/290] Update to release protocol 1.19.30 --- build-logic/src/main/kotlin/Versions.kt | 2 +- core/build.gradle.kts | 2 +- .../geysermc/geyser/network/ConnectorServerEventHandler.java | 4 ++-- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 8d0185cc8..1aa91aee0 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -31,7 +31,7 @@ object Versions { const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" - const val protocolVersion = "f0feacd" + const val protocolVersion = "96a4daf" const val raknetVersion = "1.6.28-20220125.214016-6" const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0d1c16825..62e8f1c17 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // Network libraries implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) - api("com.github.CloudburstMC.Protocol", "bedrock-v553", Versions.protocolVersion) { + api("com.github.CloudburstMC.Protocol", "bedrock-v554", Versions.protocolVersion) { exclude("com.nukkitx.network", "raknet") exclude("com.nukkitx", "nbt") } diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index bf655740f..c9a3201c1 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.network; import com.nukkitx.protocol.bedrock.BedrockPong; import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; import com.nukkitx.protocol.bedrock.BedrockServerSession; -import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; +import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultEventLoopGroup; @@ -172,7 +172,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public void onSessionCreation(@Nonnull BedrockServerSession bedrockServerSession) { try { - bedrockServerSession.setPacketCodec(Bedrock_v553.V553_CODEC); // Has the RequestNetworkSettingsPacket + bedrockServerSession.setPacketCodec(Bedrock_v554.V554_CODEC); // Has the RequestNetworkSettingsPacket bedrockServerSession.setLogging(true); bedrockServerSession.setCompressionLevel(geyser.getConfig().getBedrock().getCompressionLevel()); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(geyser, new GeyserSession(geyser, bedrockServerSession, eventLoopGroup.next()))); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index dde0b0c04..ab931e901 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; -import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; +import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -72,7 +72,7 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v553.V553_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC); } /** From 9fdbfdb0ab249f1763800cc9c3c88814831be10a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 17 Sep 2022 21:55:30 -0400 Subject: [PATCH 174/290] Fix Adventure version --- build-logic/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 1aa91aee0..edb9f8213 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -36,7 +36,7 @@ object Versions { const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" const val packetlibVersion = "3.0" - const val adventureVersion = "4.9.3" + const val adventureVersion = "4.12.0-20220629.025215-9" const val adventurePlatformVersion = "4.1.2" const val junitVersion = "4.13.1" const val checkerQualVersion = "3.19.0" From 64c03b9610e74d2c1912572b29cabbd48e148232 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 12:18:32 -0400 Subject: [PATCH 175/290] Correctly detect flying in 1.19.30 --- .../geyser/network/LoggingPacketHandler.java | 7 ++ .../BedrockAdventureSettingsTranslator.java | 18 +---- .../BedrockRequestAbilityTranslator.java | 67 +++++++++++++++++++ 3 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 7edf560e8..8d2db081a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -857,6 +857,13 @@ public class LoggingPacketHandler implements BedrockPacketHandler { return defaultHandler(packet); } + // 1.19.0 new packet + + @Override + public boolean handle(RequestAbilityPacket packet) { + return defaultHandler(packet); + } + // 1.19.30 new packet @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java index 641161127..aabc39e12 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java @@ -25,10 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; import com.nukkitx.protocol.bedrock.data.AdventureSetting; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -40,19 +37,6 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, RequestAbilityPacket packet) { + if (packet.getAbility() == Ability.FLYING) { + handle(session, packet.isBoolValue()); + } + } + + //FIXME remove after pre-1.19.30 support is dropped and merge into main method + static void handle(GeyserSession session, boolean isFlying) { + if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) { + // We should always be flying in spectator mode + session.sendAdventureSettings(); + return; + } else if (isFlying && session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { + // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling + // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE + session.sendAdventureSettings(); + return; + } + + session.setFlying(isFlying); + ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying); + session.sendDownstreamPacket(abilitiesPacket); + } +} From 4e2d750791a4a892c9850c92de41f8386beba726 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 12:20:54 -0400 Subject: [PATCH 176/290] Gatekeep RequestAbilityPackets to 1.19.30+ --- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++++ .../protocol/bedrock/BedrockRequestAbilityTranslator.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index ab931e901..f31d800c7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -95,6 +95,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() >= Bedrock_v534.V534_CODEC.getProtocolVersion(); } + public static boolean supports1_19_30(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v554.V554_CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index 1ac75079c..fe8150d40 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.nukkitx.protocol.bedrock.data.Ability; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.RequestAbilityPacket; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -42,6 +43,11 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator Date: Sun, 18 Sep 2022 13:27:16 -0400 Subject: [PATCH 177/290] Bump Protocol to fix 1.19.2x crafting --- build-logic/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index edb9f8213..47f35726d 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -31,7 +31,7 @@ object Versions { const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" - const val protocolVersion = "96a4daf" + const val protocolVersion = "fed46166" const val raknetVersion = "1.6.28-20220125.214016-6" const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" From bb2f4644beadd701a370c8bc80866707e233e4f2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:11:18 -0400 Subject: [PATCH 178/290] Fix IO_Uring being included in builds --- core/build.gradle.kts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 62e8f1c17..d5f1c7a72 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -43,8 +43,6 @@ dependencies { api("com.github.steveice10", "packetlib", Versions.packetlibVersion) { exclude("io.netty", "netty-all") - // This is still experimental - additionally, it could only really benefit standalone - exclude("io.netty.incubator", "netty-incubator-transport-native-io_uring") } implementation("com.nukkitx.network", "raknet", Versions.raknetVersion) { @@ -63,6 +61,7 @@ dependencies { implementation("io.netty", "netty-transport-native-kqueue", Versions.nettyVersion, null, "osx-x86_64") // Adventure text serialization + implementation("net.kyori", "adventure-text-serializer-gson", Versions.adventureVersion) // Remove when we remove our Adventure bump implementation("net.kyori", "adventure-text-serializer-legacy", Versions.adventureVersion) implementation("net.kyori", "adventure-text-serializer-plain", Versions.adventureVersion) @@ -75,6 +74,11 @@ dependencies { annotationProcessor(projects.ap) } +configurations.api { + // This is still experimental - additionally, it could only really benefit standalone + exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring") +} + configure { val indra = the() From f71fa9ccacec8b56e49fa2037877b704898111c6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:18:48 -0400 Subject: [PATCH 179/290] Only check for correct protocol version once --- .../geyser/network/UpstreamPacketHandler.java | 39 +++++++++++++------ settings.gradle.kts | 3 ++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 286a2eb9b..c2a91fd75 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -62,8 +62,34 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return translateAndDefault(packet); } + private boolean newProtocol = false; // TEMPORARY + + private boolean setCorrectCodec(int protocolVersion) { + BedrockPacketCodec packetCodec = GameProtocol.getBedrockCodec(protocolVersion); + if (packetCodec == null) { + String supportedVersions = GameProtocol.getAllSupportedBedrockVersions(); + if (protocolVersion > GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { + // Too early to determine session locale + session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions)); + return false; + } else if (protocolVersion < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { + session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); + return false; + } + } + + session.getUpstream().getSession().setPacketCodec(packetCodec); + return true; + } + @Override public boolean handle(RequestNetworkSettingsPacket packet) { + if (setCorrectCodec(packet.getProtocolVersion())) { + newProtocol = true; + } else { + return true; + } + // New since 1.19.30 - sent before login packet PacketCompressionAlgorithm algorithm = PacketCompressionAlgorithm.ZLIB; @@ -84,21 +110,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return true; } - BedrockPacketCodec packetCodec = GameProtocol.getBedrockCodec(loginPacket.getProtocolVersion()); - if (packetCodec == null) { - String supportedVersions = GameProtocol.getAllSupportedBedrockVersions(); - if (loginPacket.getProtocolVersion() > GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - // Too early to determine session locale - session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions)); - return true; - } else if (loginPacket.getProtocolVersion() < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); + if (!newProtocol) { + if (!setCorrectCodec(loginPacket.getProtocolVersion())) { // REMOVE WHEN ONLY 1.19.30 IS SUPPORTED OR 1.20 return true; } } - session.getUpstream().getSession().setPacketCodec(packetCodec); - // Set the block translation based off of version session.setBlockMappings(BlockRegistries.BLOCKS.forVersion(loginPacket.getProtocolVersion())); session.setItemMappings(Registries.ITEMS.forVersion(loginPacket.getProtocolVersion())); diff --git a/settings.gradle.kts b/settings.gradle.kts index 3aa66d493..f6d13ad0d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -38,6 +38,9 @@ dependencyResolutionManagement { maven("https://jitpack.io") { content { includeGroupByRegex("com\\.github\\..*") } } + + // For Adventure snapshots + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") } } From 44e60b7ad83ae36777af7d4b0920230cf74d465d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:40:44 -0400 Subject: [PATCH 180/290] An educated guess to fix Git branch --- api/base/build.gradle.kts | 1 + .../org/geysermc/geyser/api/command/CommandExecutor.java | 5 +++-- .../java/org/geysermc/geyser/api/command/CommandSource.java | 6 ++++-- .../java/org/geysermc/geyser/api/event/EventRegistrar.java | 4 +++- .../org/geysermc/geyser/api/network/BedrockListener.java | 3 +++ .../java/org/geysermc/geyser/api/network/RemoteServer.java | 3 +++ core/build.gradle.kts | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index a6fa608cc..c6cebe0ba 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -4,4 +4,5 @@ dependencies { exclude(group = "com.google.guava", module = "guava") exclude(group = "org.lanternpowered", module = "lmbda") } + compileOnlyApi("org.jetbrains", "annotations", "23.0.0") } \ No newline at end of file diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java index d384d097c..12a54ee90 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandExecutor.java @@ -25,13 +25,14 @@ package org.geysermc.geyser.api.command; +import org.checkerframework.checker.nullness.qual.NonNull; + /** * Handles executing a command. * * @param the command source */ public interface CommandExecutor { - /** * Executes the given {@link Command} with the given * {@link CommandSource}. @@ -40,5 +41,5 @@ public interface CommandExecutor { * @param command the command * @param args the arguments */ - void execute(T source, Command command, String[] args); + void execute(@NonNull T source, @NonNull Command command, @NonNull String[] args); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java index aabf0c4e8..45276e2c4 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/command/CommandSource.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.api.command; +import org.checkerframework.checker.nullness.qual.NonNull; + /** * Represents an instance capable of sending commands. */ @@ -42,7 +44,7 @@ public interface CommandSource { * * @param message the message to send */ - void sendMessage(String message); + void sendMessage(@NonNull String message); /** * Sends the given messages to the command source @@ -58,7 +60,7 @@ public interface CommandSource { /** * If this source is the console. * - * @return true if this source is the console + * @return true if this source is the console */ boolean isConsole(); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java index 7a2cc0071..064dd55f6 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/EventRegistrar.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.api.event; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.GeyserApi; /** @@ -39,7 +40,8 @@ public interface EventRegistrar { * @param object the object to wrap around * @return an event registrar instance */ - static EventRegistrar of(Object object) { + @NonNull + static EventRegistrar of(@NonNull Object object) { return GeyserApi.api().provider(EventRegistrar.class, object); } } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java b/api/geyser/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java index 58a597eb6..61fe286aa 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/network/BedrockListener.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.api.network; +import org.checkerframework.checker.nullness.qual.NonNull; + /** * The listener that handles connections from Minecraft: * Bedrock Edition. @@ -37,6 +39,7 @@ public interface BedrockListener { * * @return the listening address */ + @NonNull String address(); /** diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java b/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java index b13ae5930..d0ac6ee7e 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.api.network; +import org.jetbrains.annotations.NotNull; + /** * Represents the Java server that Geyser is connecting to. */ @@ -63,5 +65,6 @@ public interface RemoteServer { * * @return the auth type required by the remote server */ + @NotNull AuthType authType(); } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d5f1c7a72..98ddd99b8 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -84,7 +84,7 @@ configure { val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" // On Jenkins, a detached head is checked out, so indra cannot determine the branch. Fortunately, this environment variable is available. - val branchName = indra.branchName() ?: System.getenv("GIT_BRANCH") ?: "DEV" + val branchName = indra.branchName() ?: System.getenv("BRANCH") ?: "DEV" val commit = indra.commit() val git = indra.git() val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" From 8605f0a91cdd46b5b29bebe4f807d8b04be690a5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:56:30 -0400 Subject: [PATCH 181/290] Use master languages branch --- core/src/main/resources/languages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index d92904027..51d6f5ba7 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit d92904027061856248ece8382face369e9cc5d67 +Subproject commit 51d6f5ba7d85bfda318879dad34481d9ef4d488d From f11dc6d03d6234d111b27983b3003137f2f74f1d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:56:46 -0400 Subject: [PATCH 182/290] A better educated guess to fix the git branch --- core/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 98ddd99b8..89d292bed 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -84,7 +84,7 @@ configure { val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" // On Jenkins, a detached head is checked out, so indra cannot determine the branch. Fortunately, this environment variable is available. - val branchName = indra.branchName() ?: System.getenv("BRANCH") ?: "DEV" + val branchName = indra.branchName() ?: System.getenv("GIT_LOCAL_BRANCH") ?: "DEV" val commit = indra.commit() val git = indra.git() val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" From d4ab388258cb220e9fc7d534a31312bd53493fc6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:56:59 -0400 Subject: [PATCH 183/290] Remove unused annotation dependency --- api/base/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index c6cebe0ba..a6fa608cc 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -4,5 +4,4 @@ dependencies { exclude(group = "com.google.guava", module = "guava") exclude(group = "org.lanternpowered", module = "lmbda") } - compileOnlyApi("org.jetbrains", "annotations", "23.0.0") } \ No newline at end of file From fd2c24223078190d52176ec92cc637f73cd9b1cb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:59:49 -0400 Subject: [PATCH 184/290] oops --- .../java/org/geysermc/geyser/api/network/RemoteServer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java b/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java index d0ac6ee7e..8ac5d8a03 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/network/RemoteServer.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.api.network; -import org.jetbrains.annotations.NotNull; +import org.checkerframework.checker.nullness.qual.NonNull; /** * Represents the Java server that Geyser is connecting to. @@ -65,6 +65,6 @@ public interface RemoteServer { * * @return the auth type required by the remote server */ - @NotNull + @NonNull AuthType authType(); } From 9791e7b544ddbc6d1236b2b62a8f64bfab462ec5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Sep 2022 16:29:44 -0400 Subject: [PATCH 185/290] One more try on branch name --- core/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 89d292bed..f5c41ed12 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -84,7 +84,7 @@ configure { val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" // On Jenkins, a detached head is checked out, so indra cannot determine the branch. Fortunately, this environment variable is available. - val branchName = indra.branchName() ?: System.getenv("GIT_LOCAL_BRANCH") ?: "DEV" + val branchName = indra.branchName() ?: System.getenv("BRANCH_NAME") ?: "DEV" val commit = indra.commit() val git = indra.git() val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" From c84d53c827914e1985b319bcc59a167730d9f246 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 19 Sep 2022 11:22:09 -0400 Subject: [PATCH 186/290] Re-add git.properties (#3287) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- core/build.gradle.kts | 68 +++++++++++++++++++++----- core/src/main/resources/git.properties | 7 +++ 2 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 core/src/main/resources/git.properties diff --git a/core/build.gradle.kts b/core/build.gradle.kts index f5c41ed12..2825ead1f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -79,23 +79,65 @@ configurations.api { exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring") } +tasks.processResources { + // This is solely for backwards compatibility for other programs that used this file before the switch to gradle. + // It used to be generated by the maven Git-Commit-Id-Plugin + filesMatching("git.properties") { + val info = GitInfo() + expand( + "branch" to info.branch, + "buildNumber" to info.buildNumber, + "projectVersion" to project.version, + "commit" to info.commit, + "commitAbbrev" to info.commitAbbrev, + "commitMessage" to info.commitMessage, + "repository" to info.repository + ) + } +} + configure { - val indra = the() - val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java" - // On Jenkins, a detached head is checked out, so indra cannot determine the branch. Fortunately, this environment variable is available. - val branchName = indra.branchName() ?: System.getenv("BRANCH_NAME") ?: "DEV" - val commit = indra.commit() - val git = indra.git() - val gitVersion = "git-${branchName}-${commit?.name?.substring(0, 7) ?: "0000000"}" + val info = GitInfo() - replaceToken("\${version}", "${project.version} ($gitVersion)", mainFile) - replaceToken("\${gitVersion}", gitVersion, mainFile) - replaceToken("\${buildNumber}", buildNumber(), mainFile) - replaceToken("\${branch}", branchName, mainFile) - if (commit != null && commit.name != null) replaceToken("\${commit}", commit.name, mainFile) - if (git != null) replaceToken("\${repository}", git.repository.config.getString("remote", "origin", "url")) + replaceToken("\${version}", "${project.version} (${info.gitVersion})", mainFile) + replaceToken("\${gitVersion}", info.gitVersion, mainFile) + replaceToken("\${buildNumber}", info.buildNumber, mainFile) + replaceToken("\${branch}", info.branch, mainFile) + replaceToken("\${commit}", info.commit, mainFile) + replaceToken("\${repository}", info.repository, mainFile) } fun Project.buildNumber(): Int = Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") + +inner class GitInfo { + val branch: String + val commit: String + val commitAbbrev: String + + val gitVersion: String + val version: String + val buildNumber: Int + + val commitMessage: String + val repository: String + + init { + // On Jenkins, a detached head is checked out, so indra cannot determine the branch. + // Fortunately, this environment variable is available. + branch = indraGit.branchName() ?: System.getenv("BRANCH_NAME") ?: "DEV" + + val commit = indraGit.commit() + this.commit = commit?.name ?: "0".repeat(40) + commitAbbrev = commit?.name?.substring(0, 7) ?: "0".repeat(7) + + gitVersion = "git-${branch}-${commitAbbrev}" + version = "${project.version} ($gitVersion)" + buildNumber = buildNumber() + + val git = indraGit.git() + commitMessage = git?.commit()?.message ?: "" + repository = git?.repository?.config?.getString("remote", "origin", "url") ?: "" + } +} diff --git a/core/src/main/resources/git.properties b/core/src/main/resources/git.properties new file mode 100644 index 000000000..f14e55623 --- /dev/null +++ b/core/src/main/resources/git.properties @@ -0,0 +1,7 @@ +git.branch=${branch} +git.build.number=${buildNumber} +git.build.version=${projectVersion} +git.commit.id=${commit} +git.commit.id.abbrev=${commitAbbrev} +git.commit.message.full=${commitMessage} +git.remote.origin.url=${repository} From f31b183a3363792cda5f6cb476beadeb9b319f23 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 19 Sep 2022 11:26:47 -0400 Subject: [PATCH 187/290] Rename Geyser standalone jar to Geyser-Standalone.jar --- bootstrap/standalone/build.gradle.kts | 2 +- core/build.gradle.kts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index d49c7c490..3c1a10b09 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -27,7 +27,7 @@ application { } tasks.withType { - archiveBaseName.set("Geyser") + archiveBaseName.set("Geyser-Standalone") transform(Log4j2PluginsCacheFileTransformer()) } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2825ead1f..49ce2fbff 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,4 @@ import net.kyori.blossom.BlossomExtension -import net.kyori.indra.git.IndraGitExtension plugins { id("net.kyori.blossom") @@ -109,7 +108,7 @@ configure { } fun Project.buildNumber(): Int = - Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1") + System.getenv("BUILD_NUMBER")?.let { Integer.parseInt(it) } ?: -1 inner class GitInfo { val branch: String From 7cd71f570fd5cc314e9c581d5f78dbe093f45c92 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 20 Sep 2022 13:18:41 -0400 Subject: [PATCH 188/290] Fix some ordering that regressed some behavior --- .../bungeecord/GeyserBungeePlugin.java | 26 +++++++++---------- .../platform/spigot/GeyserSpigotPlugin.java | 18 ++++++------- .../velocity/GeyserVelocityPlugin.java | 18 ++++++------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 13604a3d4..d6b252473 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -72,6 +72,8 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { @Override public void onLoad() { + GeyserLocale.init(this); + // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { @@ -86,8 +88,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { getLogger().warning("/_____________\\"); } - GeyserLocale.init(this); - if (!getDataFolder().exists()) getDataFolder().mkdir(); @@ -117,17 +117,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { return; } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); - } - - geyserConfig.loadFloodgate(this); - if (getProxy().getConfig().getListeners().size() == 1) { ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0]; @@ -148,6 +137,17 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } } + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { + geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + return; + } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { + // Floodgate installed means that the user wants Floodgate authentication + geyserLogger.debug("Auto-setting to Floodgate authentication."); + geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); + } + + geyserConfig.loadFloodgate(this); + // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating // task that waits for a field to be filled which is set after the plugin enable // process is complete diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 60b1cfa21..e6bc8d984 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -164,15 +164,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - this.getPluginLoader().disablePlugin(this); - } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); - } - // By default this should be localhost but may need to be changed in some circumstances if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { geyserConfig.setAutoconfiguredRemote(true); @@ -187,6 +178,15 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.getBedrock().setPort(Bukkit.getPort()); } + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) { + geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); + this.getPluginLoader().disablePlugin(this); + } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) { + // Floodgate installed means that the user wants Floodgate authentication + geyserLogger.debug("Auto-setting to Floodgate authentication."); + geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); + } + geyserConfig.loadFloodgate(this); // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index dc31b3fdd..e92bb6cf2 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -88,6 +88,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Override public void onEnable() { + try { + Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class); + } catch (NoSuchMethodException e) { + // velocitypowered.com has a build that is very outdated + logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " + + "that has likely been downloaded is very outdated and does not support 1.19."); + return; + } + GeyserLocale.init(this); try { @@ -124,15 +133,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); - try { - Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class); - } catch (NoSuchMethodException e) { - // velocitypowered.com has a build that is very outdated - logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " + - "that has likely been downloaded is very outdated and does not support 1.19."); - return; - } - // Remove this in like a year try { // Should only exist on 1.0 From 98cfdb0b339213cf2558db525762a00199c77da2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 20 Sep 2022 14:25:39 -0400 Subject: [PATCH 189/290] Fix epoll on at least standalone --- core/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 49ce2fbff..ef1df3dea 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { api("com.github.GeyserMC", "MCAuthLib", Versions.mcauthlibVersion) api("com.github.GeyserMC", "MCProtocolLib", Versions.mcprotocollibversion) { + exclude("io.netty", "netty-all") exclude("com.github.GeyserMC", "packetlib") exclude("com.github.GeyserMC", "mcauthlib") } From 8beae31cee80e94e773c37c15a2956034f1d3e69 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 20 Sep 2022 16:02:38 -0400 Subject: [PATCH 190/290] Copy what Floodgate does for artifact publishing --- Jenkinsfile | 3 +-- .../geyser.publish-conventions.gradle.kts | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 28f9e7a37..0123a2771 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,7 +29,6 @@ pipeline { when { anyOf { branch "master" - branch "feature/extensions" } } @@ -50,7 +49,7 @@ pipeline { rootDir: "", useWrapper: true, buildFile: 'build.gradle.kts', - tasks: 'build artifactoryPublish', + tasks: 'artifactoryPublish', deployerId: "GRADLE_DEPLOYER", resolverId: "GRADLE_RESOLVER" ) diff --git a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts index f1cb8b139..68ab59337 100644 --- a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts @@ -5,24 +5,27 @@ plugins { } publishing { - publications.create("mavenJava") { - groupId = project.group as String - artifactId = project.name - version = project.version as String + publications { + create("mavenJava") { + groupId = project.group as String + artifactId = project.name + version = project.version as String - artifact(tasks["shadowJar"]) - artifact(tasks["sourcesJar"]) + artifact(tasks["shadowJar"]) + artifact(tasks["sourcesJar"]) + } } } artifactory { + setContextUrl("https://repo.opencollab.dev/artifactory") publish { repository { setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") setMavenCompatible(true) } defaults { - publishConfigs("archives") + publications("mavenJava") setPublishArtifacts(true) setPublishPom(true) setPublishIvy(false) From 55f7253a98d6d76e3c7d8bc40a705c3d7533d89b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Sep 2022 12:27:16 -0400 Subject: [PATCH 191/290] Let biomes NBT be parsed by 1.19.30 --- .../java/org/geysermc/geyser/registry/Registries.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 4b361ba4f..2c1c51baf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; import com.github.steveice10.packetlib.packet.Packet; import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; @@ -179,5 +180,15 @@ public final class Registries { // Create registries that require other registries to load first POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new); ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new); + + // TEMPORARY FIX TO MAKE OLD BIOMES NBT WORK WITH 1.19.30 + NbtMapBuilder biomesNbt = NbtMap.builder(); + for (Map.Entry entry : BIOMES_NBT.get().entrySet()) { + String key = entry.getKey(); + NbtMapBuilder value = ((NbtMap) entry.getValue()).toBuilder(); + value.put("name_hash", key); + biomesNbt.put(key, value.build()); + } + BIOMES_NBT.set(biomesNbt.build()); } } \ No newline at end of file From 5206bc3b993950e323aaac15a01324ff285a6131 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Sep 2022 12:49:38 -0400 Subject: [PATCH 192/290] Elaborate if secure profiles need to be disabled --- .../java/JavaLoginDisconnectTranslator.java | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index 356fe645b..0720963fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -46,10 +46,30 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator children = component.children(); for (int i = 0; i < children.size(); i++) { if (children.get(i) instanceof TextComponent child && child.content().startsWith("Outdated server!")) { // Reproduced on Paper 1.17.1 - isOutdatedMessage = true; - break; + return true; } } } } } + return false; + } - String serverDisconnectMessage = MessageTranslator.convertMessage(disconnectReason, session.locale()); - String disconnectMessage; - if (isOutdatedMessage) { - String locale = session.locale(); - PlatformType platform = session.getGeyser().getPlatformType(); - String outdatedType = (platform == PlatformType.BUNGEECORD || platform == PlatformType.VELOCITY) ? - "geyser.network.remote.outdated.proxy" : "geyser.network.remote.outdated.server"; - disconnectMessage = GeyserLocale.getPlayerLocaleString(outdatedType, locale, GameProtocol.getJavaVersions().get(0)) + '\n' - + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", locale, serverDisconnectMessage); - } else { - disconnectMessage = serverDisconnectMessage; - } - - // The client doesn't manually get disconnected so we have to do it ourselves - session.disconnect(disconnectMessage); + private boolean testForMissingProfilePublicKey(Component disconnectReason) { + return disconnectReason instanceof TranslatableComponent component && "multiplayer.disconnect.missing_public_key".equals(component.key()); } @Override From 6df9081d6e3abe9dd743e052959c3c009a41d8fb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Sep 2022 12:52:29 -0400 Subject: [PATCH 193/290] Possibly fix recipe class cast errors --- .../protocol/java/JavaUpdateRecipesTranslator.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index d11caf601..90468a9cb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -39,10 +39,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -221,7 +218,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator> groupedByIds = Arrays.stream(ingredient.getOptions()) .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item))) - .collect(Collectors.groupingBy(item -> new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount()))); + .collect(Collectors.groupingBy(item -> item == ItemDescriptorWithCount.EMPTY ? new GroupedItem(0, 0) : new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount()))); Set optionSet = new HashSet<>(groupedByIds.size()); for (Map.Entry> entry : groupedByIds.entrySet()) { if (entry.getValue().size() > 1) { @@ -236,7 +233,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Wed, 21 Sep 2022 13:39:06 -0400 Subject: [PATCH 194/290] Return to using NBT dependency provided by Protocol --- core/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ef1df3dea..4e8b92fef 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -31,7 +31,6 @@ dependencies { api("com.github.CloudburstMC.Protocol", "bedrock-v554", Versions.protocolVersion) { exclude("com.nukkitx.network", "raknet") - exclude("com.nukkitx", "nbt") } api("com.github.GeyserMC", "MCAuthLib", Versions.mcauthlibVersion) From c997dffea4c1ccacbd113298ef01949e6f0b2fb4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Sep 2022 15:29:43 -0400 Subject: [PATCH 195/290] Indicate 1.19.30 Bedrock support on the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d02d50d2b..997bbff58 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0/1.19.1x/1.19.20/1.19.21/1.19.22 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.30 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From d2b7b8c39216d2a6fe6350929c74e8b9e6388b32 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 21 Sep 2022 15:33:33 -0400 Subject: [PATCH 196/290] Set the default Bedrock version to 1.19.30 --- .../java/org/geysermc/geyser/network/GameProtocol.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index f31d800c7..4c5c099f0 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; +import com.nukkitx.protocol.bedrock.v545.Bedrock_v545; import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; import org.geysermc.geyser.session.GeyserSession; @@ -46,10 +47,7 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v544.V544_CODEC.toBuilder() - .minecraftVersion("1.19.22") - .protocolVersion(545) - .build(); + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v554.V554_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -69,10 +67,10 @@ public final class GameProtocol { .minecraftVersion("1.19.10/1.19.11") .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** 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 197/290] 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 198/290] 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); From 2c5c72f85fd1f15beefb26ce1a5794e593f98ca7 Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Fri, 23 Sep 2022 16:04:15 +0200 Subject: [PATCH 199/290] Replace particle explosion with particle block explosion in JavaExplodePacket (#3301) --- build-logic/src/main/kotlin/Versions.kt | 1 - core/build.gradle.kts | 2 -- .../java/level/JavaExplodeTranslator.java | 26 +++++++++++++------ .../java/level/JavaLevelEventTranslator.java | 6 ++--- .../level/JavaLevelParticlesTranslator.java | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 47f35726d..d492022ba 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -29,7 +29,6 @@ object Versions { const val nettyVersion = "4.1.80.Final" const val guavaVersion = "29.0-jre" const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 - const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" const val protocolVersion = "fed46166" const val raknetVersion = "1.6.28-20220125.214016-6" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 4e8b92fef..1bf227e58 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -16,8 +16,6 @@ dependencies { api("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", Versions.jacksonVersion) api("com.google.guava", "guava", Versions.guavaVersion) - api("com.nukkitx", "nbt", Versions.nbtVersion) - // Fastutil Maps implementation("com.nukkitx.fastutil", "fastutil-int-int-maps", Versions.fastutilVersion) implementation("com.nukkitx.fastutil", "fastutil-int-long-maps", Versions.fastutilVersion) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index d5ac1abba..51c508e57 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -28,9 +28,11 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.LevelEventGenericPacket; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.geyser.level.block.BlockStateValues; @@ -44,19 +46,27 @@ public class JavaExplodeTranslator extends PacketTranslator= 2.0f ? LevelEventType.PARTICLE_HUGE_EXPLODE : LevelEventType.PARTICLE_EXPLOSION); - levelEventPacket.setData(0); - levelEventPacket.setPosition(pos); + levelEventPacket.setTag(builder.build()); session.sendUpstreamPacket(levelEventPacket); + Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setRelativeVolumeDisabled(false); levelSoundEventPacket.setBabySound(false); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index b9fccc80a..797699e2b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -263,7 +263,7 @@ public class JavaLevelEventTranslator extends PacketTranslator 0) { - levelEventPacket.setEventId(2037); + levelEventPacket.setEventId(2037/*LevelEventType.SCULK_CHARGE*/); levelEventPacket.setTag( NbtMap.builder() .putInt("x", packet.getPosition().getX()) @@ -274,7 +274,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); - levelEventPacket.setEventId(2035); + levelEventPacket.setEventId(2035/*LevelEventType.PARTICLE_SCULK_SHRIEK*/); levelEventPacket.setTag( NbtMap.builder() .putInt("originX", packet.getPosition().getX()) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index c77caadee..94466a1ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -157,7 +157,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator { LevelEventGenericPacket packet = new LevelEventGenericPacket(); - packet.setEventId(2027); + packet.setEventId(2027/*LevelEventType.PARTICLE_VIBRATION_SIGNAL*/); packet.setTag( NbtMap.builder() .putCompound("origin", buildVec3PositionTag(position)) From e491cf8a17d8e49d215834671205ada10e293dcc Mon Sep 17 00:00:00 2001 From: SupremeMortal Date: Mon, 26 Sep 2022 16:43:17 +0100 Subject: [PATCH 200/290] Use Gradle's dependency catalogue feature (#3305) Move all of our dependencies to a single catalogue file to make maintenance of them easier. --- api/base/build.gradle.kts | 4 +- bootstrap/bungeecord/build.gradle.kts | 6 +- bootstrap/spigot/build.gradle.kts | 10 +-- bootstrap/sponge/build.gradle.kts | 4 +- bootstrap/standalone/build.gradle.kts | 10 +-- bootstrap/velocity/build.gradle.kts | 6 +- build-logic/src/main/kotlin/Versions.kt | 45 ---------- build-logic/src/main/kotlin/extensions.kt | 8 ++ .../kotlin/geyser.base-conventions.gradle.kts | 2 +- common/build.gradle.kts | 4 +- core/build.gradle.kts | 45 ++++------ gradle/libs.versions.toml | 89 +++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 13 files changed, 134 insertions(+), 101 deletions(-) delete mode 100644 build-logic/src/main/kotlin/Versions.kt create mode 100644 gradle/libs.versions.toml diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts index a6fa608cc..6b6fb8f46 100644 --- a/api/base/build.gradle.kts +++ b/api/base/build.gradle.kts @@ -1,6 +1,6 @@ dependencies { - api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) - api("org.geysermc.event", "events", Versions.eventsVersion) { + api(libs.cumulus) + api(libs.events) { exclude(group = "com.google.guava", module = "guava") exclude(group = "org.lanternpowered", module = "lmbda") } diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 9f3b49b67..3e0e9c147 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -1,9 +1,7 @@ -val bungeeVersion = "a7c6ede"; - dependencies { api(projects.core) - implementation("net.kyori", "adventure-text-serializer-bungeecord", Versions.adventurePlatformVersion) + implementation(libs.adventure.text.serializer.bungeecord) } platformRelocate("net.md_5.bungee.jni") @@ -12,7 +10,7 @@ platformRelocate("io.netty.channel.kqueue") // This is not used because relocati platformRelocate("net.kyori") // These dependencies are already present on the platform -provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", bungeeVersion) +provided(libs.bungeecord.proxy) application { mainClass.set("org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain") diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 5a459a09b..31e68ed92 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -6,19 +6,19 @@ val commodoreVersion = "2.2" dependencies { api(projects.core) - implementation("org.geysermc.geyser.adapters", "spigot-all", adaptersVersion) + implementation(libs.adapters.spigot) - implementation("me.lucko", "commodore", commodoreVersion) + implementation(libs.commodore) - implementation("net.kyori", "adventure-text-serializer-bungeecord", Versions.adventurePlatformVersion) + implementation(libs.adventure.text.serializer.bungeecord) // Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19 - compileOnly("io.papermc.paper", "paper-api", paperVersion) { + compileOnly(libs.paper.api) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } } - compileOnly("io.papermc.paper", "paper-mojangapi", paperVersion) { + compileOnly(libs.paper.mojangapi) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } diff --git a/bootstrap/sponge/build.gradle.kts b/bootstrap/sponge/build.gradle.kts index 2850b2c5e..8765c4390 100644 --- a/bootstrap/sponge/build.gradle.kts +++ b/bootstrap/sponge/build.gradle.kts @@ -1,5 +1,3 @@ -val spongeVersion = "7.1.0" - dependencies { api(projects.core) } @@ -18,7 +16,7 @@ exclude("org.slf4j:*") exclude("org.ow2.asm:*") // These dependencies are already present on the platform -provided("org.spongepowered", "spongeapi", spongeVersion) +provided(libs.sponge.api) application { mainClass.set("org.geysermc.geyser.platform.sponge.GeyserSpongeMain") diff --git a/bootstrap/standalone/build.gradle.kts b/bootstrap/standalone/build.gradle.kts index 3c1a10b09..9c2194445 100644 --- a/bootstrap/standalone/build.gradle.kts +++ b/bootstrap/standalone/build.gradle.kts @@ -6,20 +6,16 @@ val jlineVersion = "3.21.0" dependencies { api(projects.core) - implementation("net.minecrell", "terminalconsoleappender", terminalConsoleVersion) { + implementation(libs.terminalconsoleappender) { exclude("org.apache.logging.log4j", "log4j-core") exclude("org.jline", "jline-reader") exclude("org.jline", "jline-terminal") exclude("org.jline", "jline-terminal-jna") } - implementation("org.jline", "jline-terminal", jlineVersion) - implementation("org.jline", "jline-terminal-jna", jlineVersion) - implementation("org.jline", "jline-reader", jlineVersion) + implementation(libs.bundles.jline) - implementation("org.apache.logging.log4j", "log4j-api", Versions.log4jVersion) - implementation("org.apache.logging.log4j", "log4j-core", Versions.log4jVersion) - implementation("org.apache.logging.log4j", "log4j-slf4j18-impl", Versions.log4jVersion) + implementation(libs.bundles.log4j) } application { diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index ab2f85b85..8908b2afd 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -1,7 +1,5 @@ -val velocityVersion = "3.0.0" - dependencies { - annotationProcessor("com.velocitypowered", "velocity-api", velocityVersion) + annotationProcessor(libs.velocity.api) api(projects.core) } @@ -34,7 +32,7 @@ exclude("net.kyori:adventure-text-serializer-legacy:*") exclude("net.kyori:adventure-nbt:*") // These dependencies are already present on the platform -provided("com.velocitypowered", "velocity-api", velocityVersion) +provided(libs.velocity.api) application { mainClass.set("org.geysermc.geyser.platform.velocity.GeyserVelocityMain") diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt deleted file mode 100644 index d492022ba..000000000 --- a/build-logic/src/main/kotlin/Versions.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019-2022 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 - */ - -object Versions { - const val jacksonVersion = "2.13.2" - const val fastutilVersion = "8.5.2" - const val nettyVersion = "4.1.80.Final" - const val guavaVersion = "29.0-jre" - const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 - const val websocketVersion = "1.5.1" - const val protocolVersion = "fed46166" - const val raknetVersion = "1.6.28-20220125.214016-6" - const val mcauthlibVersion = "d9d773e" - const val mcprotocollibversion = "9f78bd5" - const val packetlibVersion = "3.0" - const val adventureVersion = "4.12.0-20220629.025215-9" - const val adventurePlatformVersion = "4.1.2" - const val junitVersion = "4.13.1" - const val checkerQualVersion = "3.19.0" - const val cumulusVersion = "1.1.1" - const val eventsVersion = "1.0-SNAPSHOT" - const val log4jVersion = "2.17.1" -} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 43cdafdcc..0c01913d2 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -25,7 +25,9 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Project +import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.provider.Provider import org.gradle.kotlin.dsl.named fun Project.isSnapshot(): Boolean = @@ -64,5 +66,11 @@ fun Project.provided(pattern: String, name: String, version: String, excludedOn: fun Project.provided(dependency: ProjectDependency) = provided(dependency.group!!, dependency.name, dependency.version!!) +fun Project.provided(dependency: MinimalExternalModuleDependency) = + provided(dependency.module.group, dependency.module.name, dependency.versionConstraint.requiredVersion) + +fun Project.provided(provider: Provider) = + provided(provider.get()) + private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = if (excludedOn and bit > 0) section else "" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 2ea5d88a4..ac652764b 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -4,7 +4,7 @@ plugins { } dependencies { - compileOnly("org.checkerframework", "checker-qual", Versions.checkerQualVersion) + compileOnly("org.checkerframework", "checker-qual", "3.19.0") } tasks { diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 6c1414105..44f97b9fa 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,4 +1,4 @@ dependencies { - api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion) - api("com.google.code.gson", "gson", Versions.gsonVersion) + api(libs.cumulus) + api(libs.gson) } \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1bf227e58..1ab99990a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -11,59 +11,50 @@ dependencies { api(projects.common) // Jackson JSON and YAML serialization - api("com.fasterxml.jackson.core", "jackson-annotations", Versions.jacksonVersion) - api("com.fasterxml.jackson.core", "jackson-databind", Versions.jacksonVersion + ".1") // Extra .1 as databind is a slightly different version - api("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", Versions.jacksonVersion) - api("com.google.guava", "guava", Versions.guavaVersion) + api(libs.bundles.jackson) + api(libs.guava) // Fastutil Maps - implementation("com.nukkitx.fastutil", "fastutil-int-int-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-int-long-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-int-byte-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-int-boolean-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-object-int-maps", Versions.fastutilVersion) - implementation("com.nukkitx.fastutil", "fastutil-object-object-maps", Versions.fastutilVersion) + implementation(libs.bundles.fastutil) // Network libraries - implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) + implementation(libs.websocket) - api("com.github.CloudburstMC.Protocol", "bedrock-v554", Versions.protocolVersion) { + api(libs.protocol) { exclude("com.nukkitx.network", "raknet") } - api("com.github.GeyserMC", "MCAuthLib", Versions.mcauthlibVersion) - api("com.github.GeyserMC", "MCProtocolLib", Versions.mcprotocollibversion) { + api(libs.mcauthlib) + api(libs.mcprotocollib) { exclude("io.netty", "netty-all") exclude("com.github.GeyserMC", "packetlib") exclude("com.github.GeyserMC", "mcauthlib") } - api("com.github.steveice10", "packetlib", Versions.packetlibVersion) { + api(libs.packetlib) { exclude("io.netty", "netty-all") } - implementation("com.nukkitx.network", "raknet", Versions.raknetVersion) { + implementation(libs.raknet) { exclude("io.netty", "*"); } - implementation("io.netty", "netty-resolver-dns", Versions.nettyVersion) - implementation("io.netty", "netty-resolver-dns-native-macos", Versions.nettyVersion, null, "osx-x86_64") - implementation("io.netty", "netty-codec-haproxy", Versions.nettyVersion) + implementation(libs.netty.resolver.dns) + implementation(libs.netty.resolver.dns.native.macos) { artifact { classifier = "osx-x86_64" } } + implementation(libs.netty.codec.haproxy) // Network dependencies we are updating ourselves - api("io.netty", "netty-handler", Versions.nettyVersion) + api(libs.netty.handler) - implementation("io.netty", "netty-transport-native-epoll", Versions.nettyVersion, null, "linux-x86_64") - implementation("io.netty", "netty-transport-native-epoll", Versions.nettyVersion, null, "linux-aarch_64") - implementation("io.netty", "netty-transport-native-kqueue", Versions.nettyVersion, null, "osx-x86_64") + implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } } + implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } } + implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } } // Adventure text serialization - implementation("net.kyori", "adventure-text-serializer-gson", Versions.adventureVersion) // Remove when we remove our Adventure bump - implementation("net.kyori", "adventure-text-serializer-legacy", Versions.adventureVersion) - implementation("net.kyori", "adventure-text-serializer-plain", Versions.adventureVersion) + implementation(libs.bundles.adventure) // Test - testImplementation("junit", "junit", Versions.junitVersion) + testImplementation(libs.junit) // Annotation Processors compileOnly(projects.ap) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..d5d5fab30 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,89 @@ +[versions] +jackson = "2.13.4" +fastutil = "8.5.2" +netty = "4.1.80.Final" +guava = "29.0-jre" +gson = "2.3.1" # Provided by Spigot 1.8.8 +websocket = "1.5.1" +protocol = "fed46166" +raknet = "1.6.28-20220125.214016-6" +mcauthlib = "d9d773e" +mcprotocollib = "9f78bd5" +packetlib = "3.0" +adventure = "4.12.0-20220629.025215-9" +adventure-platform = "4.1.2" +junit = "4.13.1" +checkerframework = "3.19.0" +cumulus = "1.1.1" +events = "1.0-SNAPSHOT" +log4j = "2.17.1" +jline = "3.21.0" +terminalconsoleappender = "1.2.0" +paper = "1.19-R0.1-SNAPSHOT" +viaversion = "4.0.0" +adapters = "1.5-SNAPSHOT" +commodore = "2.2" +bungeecord = "a7c6ede" +velocity = "3.0.0" +sponge = "7.1.0" + +[libraries] +jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } +jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" } + +fastutil-int-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-int-maps", version.ref = "fastutil" } +fastutil-int-long-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-long-maps", version.ref = "fastutil" } +fastutil-int-byte-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-byte-maps", version.ref = "fastutil" } +fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" } +fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" } +fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" } + +adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump +adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } +adventure-text-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" } +adventure-text-serializer-bungeecord = { group = "net.kyori", name = "adventure-text-serializer-bungeecord", version.ref = "adventure-platform" } + +netty-resolver-dns = { group = "io.netty", name = "netty-resolver-dns", version.ref = "netty" } +netty-resolver-dns-native-macos = { group = "io.netty", name = "netty-resolver-dns-native-macos", version.ref = "netty" } +netty-codec-haproxy = { group = "io.netty", name = "netty-codec-haproxy", version.ref = "netty" } +netty-handler = { group = "io.netty", name = "netty-handler", version.ref = "netty" } +netty-transport-native-epoll = { group = "io.netty", name = "netty-transport-native-epoll", version.ref = "netty" } +netty-transport-native-kqueue = { group = "io.netty", name = "netty-transport-native-kqueue", version.ref = "netty" } + +log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" } +log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" } +log4j-slf4j18-impl = { group = "org.apache.logging.log4j", name = "log4j-slf4j18-impl", version.ref = "log4j" } + +jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = "jline" } +jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" } +jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jline" } + +paper-api = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } +paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "paper" } + +adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" } +bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" } +checker-qual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerframework" } +commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } +cumulus = { group = "org.geysermc.cumulus", name = "cumulus", version.ref = "cumulus" } +events = { group = "org.geysermc.event", name = "events", version.ref = "events" } +guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } +gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } +mcprotocollib = { group = "com.github.GeyserMC", name = "MCProtocolLib", version.ref = "mcprotocollib" } +packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" } +protocol = { group = "com.github.CloudburstMC.Protocol", name = "bedrock-v554", version.ref = "protocol" } +raknet = { group = "com.nukkitx.network", name = "raknet", version.ref = "raknet" } +sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" } +terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } +velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } +websocket = { group = "org.java-websocket", name = "Java-WebSocket", version.ref = "websocket" } + +[bundles] +jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ] +fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ] +adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] +log4j = [ "log4j-api", "log4j-core", "log4j-slf4j18-impl" ] +jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb8790..8049c684f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From a84362af2cd6acc5bb40e39c1263471512ab2f51 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 26 Sep 2022 11:54:46 -0400 Subject: [PATCH 201/290] Bump Protocol to fix cartographer tables --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d5d5fab30..5f9d72d57 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.80.Final" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "fed46166" +protocol = "2.9.12-20220926.095446-6" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" mcprotocollib = "9f78bd5" @@ -74,7 +74,7 @@ junit = { group = "junit", name = "junit", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcprotocollib = { group = "com.github.GeyserMC", name = "MCProtocolLib", version.ref = "mcprotocollib" } packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" } -protocol = { group = "com.github.CloudburstMC.Protocol", name = "bedrock-v554", version.ref = "protocol" } +protocol = { group = "com.nukkitx.protocol", name = "bedrock-v554", version.ref = "protocol" } raknet = { group = "com.nukkitx.network", name = "raknet", version.ref = "raknet" } sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } From 1b6cfad5ad7e6da03288890ad1f1e8fe91e6d091 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 27 Sep 2022 19:24:50 -0400 Subject: [PATCH 202/290] Fix ghost blocks when insta-mining on 1.19+ Fixes #3113 --- .../command/defaults/OffhandCommand.java | 2 +- .../populator/BlockRegistryPopulator.java | 2 +- .../geyser/registry/type/BlockMapping.java | 2 +- .../geyser/session/GeyserSession.java | 2 +- .../geyser/session/cache/WorldCache.java | 61 ++++++------------- ...BedrockInventoryTransactionTranslator.java | 13 ++-- .../player/BedrockActionTranslator.java | 7 ++- .../entity/player/BedrockEmoteTranslator.java | 2 +- .../java/level/JavaBlockUpdateTranslator.java | 3 +- .../JavaSectionBlocksUpdateTranslator.java | 3 +- .../org/geysermc/geyser/util/ChunkUtils.java | 1 - 11 files changed, 36 insertions(+), 62 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java index bba2e8d21..0015149be 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java @@ -47,7 +47,7 @@ public class OffhandCommand extends GeyserCommand { } ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, - Direction.DOWN, session.getWorldCache().nextPredictionSequence()); + Direction.DOWN, 0); session.sendDownstreamPacket(releaseItemPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index ce8f05ed8..afc79082a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -234,7 +234,7 @@ public final class BlockRegistryPopulator { BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); JsonNode hardnessNode = entry.getValue().get("block_hardness"); if (hardnessNode != null) { - builder.hardness(hardnessNode.doubleValue()); + builder.hardness(hardnessNode.floatValue()); } JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand"); diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java index cd91f64d1..34cde0acf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java @@ -45,7 +45,7 @@ public class BlockMapping { */ int javaBlockId; - double hardness; + float hardness; boolean canBreakWithHand; /** * The index of this collision in collision.json diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 2fd1edd44..67aedec15 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1311,7 +1311,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private boolean disableBlocking() { if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, - Vector3i.ZERO, Direction.DOWN, worldCache.nextPredictionSequence()); + Vector3i.ZERO, Direction.DOWN, 0); sendDownstreamPacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return true; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index 30f8c3ba8..b3d0518b3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -28,17 +28,17 @@ package org.geysermc.geyser.session.cache; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.ChunkUtils; import java.util.Iterator; -import java.util.Map; public final class WorldCache { private final GeyserSession session; @@ -59,7 +59,7 @@ public final class WorldCache { private int trueTitleFadeOutTime; private int currentSequence; - private final Map unverifiedPredictions = new Object2ObjectOpenHashMap<>(1); + private final Object2IntMap unverifiedPredictions = new Object2IntOpenHashMap<>(1); public WorldCache(GeyserSession session) { this.session = session; @@ -135,30 +135,33 @@ public final class WorldCache { /* Code to support the prediction structure introduced in Java Edition 1.19.0 Blocks can be rolled back if invalid, but this requires some client-side information storage. */ + /** + * This does not need to be called for all player action packets (as of 1.19.2) and can be set to 0 if blocks aren't + * changed in the action. + */ public int nextPredictionSequence() { return ++currentSequence; } /** - * Stores a record of a block at a certain position to rollback in the event it is incorrect. + * Stores a note that this position may need to be rolled back at a future point in time. */ - public void addServerCorrectBlockState(Vector3i position, int blockState) { + public void markPositionInSequence(Vector3i position) { if (session.isEmulatePost1_18Logic()) { // Cheap hack // On non-Bukkit platforms, ViaVersion will always confirm the sequence before the block is updated, // meaning we'd send two block updates after (ChunkUtils.updateBlockClientSide in endPredictionsUpTo // and the packet updating from the client) - this.unverifiedPredictions.compute(position, ($, serverVerifiedState) -> serverVerifiedState == null - ? new ServerVerifiedState(currentSequence, blockState) : serverVerifiedState.setData(currentSequence, blockState)); + this.unverifiedPredictions.put(position, currentSequence); } } - public void updateServerCorrectBlockState(Vector3i position) { - if (this.unverifiedPredictions.isEmpty()) { - return; + public void updateServerCorrectBlockState(Vector3i position, int blockState) { + if (!this.unverifiedPredictions.isEmpty()) { + this.unverifiedPredictions.removeInt(position); } - this.unverifiedPredictions.remove(position); + ChunkUtils.updateBlock(session, blockState, position); } public void endPredictionsUpTo(int sequence) { @@ -166,40 +169,16 @@ public final class WorldCache { return; } - Iterator> it = this.unverifiedPredictions.entrySet().iterator(); + Iterator> it = Object2IntMaps.fastIterator(this.unverifiedPredictions); while (it.hasNext()) { - Map.Entry entry = it.next(); - ServerVerifiedState serverVerifiedState = entry.getValue(); - if (serverVerifiedState.sequence <= sequence) { + Object2IntMap.Entry entry = it.next(); + if (entry.getIntValue() <= sequence) { // This block may be out of sync with the server // In 1.19.0 Java, you can verify this by trying to mine in spawn protection - ChunkUtils.updateBlockClientSide(session, serverVerifiedState.blockState, entry.getKey()); + Vector3i position = entry.getKey(); + ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().getBlockAt(session, position), position); it.remove(); } } } - - private static class ServerVerifiedState { - private int sequence; - private int blockState; - - ServerVerifiedState(int sequence, int blockState) { - this.sequence = sequence; - this.blockState = blockState; - } - - ServerVerifiedState setData(int sequence, int blockState) { - this.sequence = sequence; - this.blockState = blockState; - return this; - } - - @Override - public String toString() { - return "ServerVerifiedState{" + - "sequence=" + sequence + - ", blockState=" + blockState + - '}'; - } - } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 49eb30973..436f26cb9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -127,7 +127,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) { // Activate the workaround - we should trigger the offhand now ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, - Direction.DOWN, session.getWorldCache().nextPredictionSequence()); + Direction.DOWN, 0); session.sendDownstreamPacket(swapHandsPacket); if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index 564a807b4..cd965e128 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -35,7 +35,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; -import org.geysermc.geyser.util.ChunkUtils; @Translator(packet = ClientboundBlockUpdatePacket.class) public class JavaBlockUpdateTranslator extends PacketTranslator { @@ -45,7 +44,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator { @@ -38,7 +37,7 @@ public class JavaSectionBlocksUpdateTranslator extends PacketTranslator Date: Thu, 29 Sep 2022 23:52:51 +0700 Subject: [PATCH 203/290] Remove sonarcloud workflow (#3314) --- .github/workflows/sonarcloud.yml | 36 -------------------------------- 1 file changed, 36 deletions(-) delete mode 100644 .github/workflows/sonarcloud.yml diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index 598cab46a..000000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: SonarCloud -on: - push: - branches: - - master -jobs: - build: - name: SonarCloud - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - submodules: true - - name: Set up JDK 17 - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: 17 - - name: Cache SonarCloud packages - uses: actions/cache@v1 - with: - path: ~/.sonar/cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar - - name: Cache Maven packages - uses: actions/cache@v1 - with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 - - name: Build and analyze - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=GeyserMC_Geyser \ No newline at end of file From c3c2e18f5074d6c57e443d76e2e1fa4323e527dd Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 29 Sep 2022 20:57:45 -0400 Subject: [PATCH 204/290] Fix Geyser Standalone archive on github workflows (#3325) --- .github/workflows/pullrequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 9d925c4dc..cb55c2675 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -24,7 +24,7 @@ jobs: if: success() with: name: Geyser Standalone - path: bootstrap/standalone/build/libs/Geyser.jar + path: bootstrap/standalone/build/libs/Geyser-Standalone.jar - name: Archive artifacts (Geyser Spigot) uses: actions/upload-artifact@v2 if: success() From 47d14e12eb7696cf42202240854dde9f07a95c9d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 30 Sep 2022 11:58:09 -0400 Subject: [PATCH 205/290] Geyser now requires 1.13.2+ on Spigot --- .../platform/spigot/GeyserSpigotPlugin.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index e6bc8d984..65de068af 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -32,6 +32,7 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import io.netty.buffer.ByteBuf; import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; +import org.bukkit.block.data.BlockData; import org.bukkit.command.CommandMap; import org.bukkit.command.PluginCommand; import org.bukkit.event.EventHandler; @@ -99,18 +100,22 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onLoad() { + GeyserLocale.init(this); + try { - // AvailableCommandsSerializer_v291 complains otherwise + // AvailableCommandsSerializer_v291 complains otherwise - affects at least 1.8 ByteBuf.class.getMethod("writeShortLE", int.class); - } catch (NoSuchMethodException e) { + // Only available in 1.13.x + Class.forName("org.bukkit.event.server.ServerLoadEvent"); + // We depend on this as a fallback in certain scenarios + BlockData.class.getMethod("getAsString"); + } catch (ClassNotFoundException | NoSuchMethodException e) { getLogger().severe("*********************************************"); getLogger().severe(""); getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header")); - getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.12.2")); + getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2")); getLogger().severe(""); getLogger().severe("*********************************************"); - - Bukkit.getPluginManager().disablePlugin(this); return; } @@ -124,14 +129,10 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); getLogger().severe(""); getLogger().severe("*********************************************"); - - Bukkit.getPluginManager().disablePlugin(this); return; } } - GeyserLocale.init(this); - // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed try { if (!getDataFolder().exists()) { @@ -157,6 +158,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onEnable() { + if (this.geyserConfig == null) { + // We failed to initialize correctly + Bukkit.getPluginManager().disablePlugin(this); + return; + } + // Remove this in like a year if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION)); From c31bd456f6bd93c0da3cc4db1119bb94bf493d1f Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Fri, 30 Sep 2022 18:12:27 +0200 Subject: [PATCH 206/290] Fix entity motion (arrows now rotate correctly) (#3307) --- .../geysermc/geyser/entity/type/Entity.java | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index 1db2e6117..c4046bcf3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -216,19 +216,41 @@ public class Entity { } public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) { - setYaw(yaw); - setPitch(pitch); - setHeadYaw(headYaw); - setOnGround(isOnGround); - this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); + position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); - MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); + MoveEntityDeltaPacket moveEntityPacket = new MoveEntityDeltaPacket(); moveEntityPacket.setRuntimeEntityId(geyserId); - moveEntityPacket.setPosition(position); - moveEntityPacket.setRotation(getBedrockRotation()); - moveEntityPacket.setOnGround(isOnGround); - moveEntityPacket.setTeleported(false); - + if (relX != 0.0) { + moveEntityPacket.setX(position.getX()); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X); + } + if (relY != 0.0) { + moveEntityPacket.setY(position.getY()); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Y); + } + if (relZ != 0.0) { + moveEntityPacket.setZ(position.getZ()); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Z); + } + if (pitch != this.pitch) { + this.pitch = pitch; + moveEntityPacket.setPitch(pitch); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH); + } + if (yaw != this.yaw) { + this.yaw = yaw; + moveEntityPacket.setYaw(yaw); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW); + } + if (headYaw != this.headYaw) { + this.headYaw = headYaw; + moveEntityPacket.setHeadYaw(headYaw); + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_HEAD_YAW); + } + setOnGround(isOnGround); + if (isOnGround) { + moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND); + } session.sendUpstreamPacket(moveEntityPacket); } From cb864b3c98a9df66fef4f9319a5257eaa1c44616 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 30 Sep 2022 21:21:37 -0400 Subject: [PATCH 207/290] Fix NPE with furnace minecart with NBT data --- .../geyser/registry/populator/ItemRegistryPopulator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 60a16245c..6c01ee9d2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -567,6 +567,7 @@ public class ItemRegistryPopulator { .bedrockData(0) .bedrockBlockId(-1) .stackSize(1) + .customItemOptions(Object2IntMaps.emptyMap()) // TODO check for custom items with furnace minecart .build()); creativeItems.add(ItemData.builder() From 7653a626afe8ad6320299ef5a39437ad271846fd Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 2 Oct 2022 16:43:14 -0400 Subject: [PATCH 208/290] Update Sponge to API 8 (#2611) --- .../bungeecord/GeyserBungeeDumpInfo.java | 6 +- .../command/GeyserBungeeCommandExecutor.java | 3 + .../platform/spigot/GeyserSpigotDumpInfo.java | 5 +- .../command/GeyserSpigotCommandExecutor.java | 3 + bootstrap/sponge/build.gradle.kts | 18 +- .../platform/sponge/GeyserSpongeDumpInfo.java | 35 ++-- .../platform/sponge/GeyserSpongeLogger.java | 2 +- .../sponge/GeyserSpongePingPassthrough.java | 47 +++-- .../platform/sponge/GeyserSpongePlugin.java | 175 +++++++++++------- .../command/GeyserSpongeCommandExecutor.java | 65 ++++--- .../command/GeyserSpongeCommandManager.java | 30 ++- .../sponge/command/SpongeCommandSource.java | 17 +- .../resources/META-INF/sponge_plugins.json | 30 +++ .../sponge/src/main/resources/pack.mcmeta | 6 + .../velocity/GeyserVelocityDumpInfo.java | 5 +- .../GeyserVelocityCommandExecutor.java | 3 + .../kotlin/geyser.base-conventions.gradle.kts | 2 +- core/src/main/resources/languages | 2 +- core/src/main/resources/mappings | 2 +- gradle/libs.versions.toml | 2 +- 20 files changed, 293 insertions(+), 165 deletions(-) create mode 100644 bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json create mode 100644 bootstrap/sponge/src/main/resources/pack.mcmeta diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java index 938e2fc3a..2278d99d9 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java @@ -52,10 +52,8 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo { this.plugins = new ArrayList<>(); for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) { - String hostname; - if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) { - hostname = listener.getHost().getHostString(); - } else { + String hostname = listener.getHost().getHostString(); + if (!AsteriskSerializer.showSensitive && !(hostname.equals("") || hostname.equals("0.0.0.0"))) { hostname = "***"; } this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort())); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java index 6575f047c..2d02c9950 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java @@ -69,6 +69,9 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor return; } command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); + commandSender.sendMessage(ChatColor.RED + message); } } else { this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java index 8055a375f..92c2fe16b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java @@ -51,8 +51,9 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo { this.platformVersion = Bukkit.getVersion(); this.platformAPIVersion = Bukkit.getBukkitVersion(); this.onlineMode = Bukkit.getOnlineMode(); - if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) { - this.serverIP = Bukkit.getIp(); + String ip = Bukkit.getIp(); + if (AsteriskSerializer.showSensitive || (ip.equals("") || ip.equals("0.0.0.0"))) { + this.serverIP = ip; } else { this.serverIP = "***"; } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java index 52779db23..61d394214 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java @@ -66,6 +66,9 @@ public class GeyserSpigotCommandExecutor extends GeyserCommandExecutor implement } geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); return true; + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale()); + commandSender.sendMessage(ChatColor.RED + message); } } else { getCommand("help").execute(session, commandSender, new String[0]); diff --git a/bootstrap/sponge/build.gradle.kts b/bootstrap/sponge/build.gradle.kts index 8765c4390..3d89e8649 100644 --- a/bootstrap/sponge/build.gradle.kts +++ b/bootstrap/sponge/build.gradle.kts @@ -7,13 +7,8 @@ platformRelocate("io.netty") platformRelocate("it.unimi.dsi.fastutil") platformRelocate("com.google.common") platformRelocate("com.google.guava") -platformRelocate("net.kyori") - -// Exclude these dependencies -exclude("com.google.code.gson:*") -exclude("org.yaml:*") -exclude("org.slf4j:*") -exclude("org.ow2.asm:*") +platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl") +platformRelocate("net.kyori.adventure.nbt") // These dependencies are already present on the platform provided(libs.sponge.api) @@ -30,5 +25,14 @@ tasks.withType { exclude(dependency("org.yaml:.*")) exclude(dependency("org.slf4j:.*")) exclude(dependency("org.ow2.asm:.*")) + + // Exclude all Kyori dependencies except the legacy NBT serializer and NBT + exclude(dependency("net.kyori:adventure-api:.*")) + exclude(dependency("net.kyori:examination-api:.*")) + exclude(dependency("net.kyori:examination-string:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-gson:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*")) + exclude(dependency("net.kyori:adventure-text-serializer-plain:.*")) + exclude(dependency("net.kyori:adventure-key:.*")) } } \ No newline at end of file diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java index e65684af2..fc1bff3ef 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java @@ -27,12 +27,18 @@ package org.geysermc.geyser.platform.sponge; import lombok.Getter; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.text.AsteriskSerializer; import org.spongepowered.api.Platform; import org.spongepowered.api.Sponge; -import org.spongepowered.api.plugin.PluginContainer; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.metadata.PluginMetadata; +import org.spongepowered.plugin.metadata.model.PluginContributor; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Getter public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { @@ -44,18 +50,25 @@ public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { private final List plugins; GeyserSpongeDumpInfo() { - super(); - PluginContainer container = Sponge.getPlatform().getContainer(Platform.Component.IMPLEMENTATION); - this.platformName = container.getName(); - this.platformVersion = container.getVersion().get(); - this.onlineMode = Sponge.getServer().getOnlineMode(); - this.serverIP = Sponge.getServer().getBoundAddress().get().getHostString(); - this.serverPort = Sponge.getServer().getBoundAddress().get().getPort(); + PluginContainer container = Sponge.platform().container(Platform.Component.IMPLEMENTATION); + PluginMetadata platformMeta = container.metadata(); + this.platformName = platformMeta.name().orElse("unknown"); + this.platformVersion = platformMeta.version().getQualifier(); + this.onlineMode = Sponge.server().isOnlineModeEnabled(); + Optional socketAddress = Sponge.server().boundAddress(); + String hostString = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown"); + if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0") || hostString.equals("unknown"))) { + this.serverIP = hostString; + } else { + this.serverIP = "***"; + } + this.serverPort = socketAddress.map(InetSocketAddress::getPort).orElse(-1); this.plugins = new ArrayList<>(); - for (PluginContainer plugin : Sponge.getPluginManager().getPlugins()) { - String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown"); - this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion().get(), pluginClass, plugin.getAuthors())); + for (PluginContainer plugin : Sponge.pluginManager().plugins()) { + PluginMetadata meta = plugin.metadata(); + List contributors = meta.contributors().stream().map(PluginContributor::name).collect(Collectors.toList()); + this.plugins.add(new PluginInfo(true, meta.name().orElse("unknown"), meta.version().toString(), meta.entrypoint(), contributors)); } } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java index 4ab4e5346..2bed78ac9 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java @@ -29,7 +29,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.GeyserLogger; -import org.slf4j.Logger; +import org.apache.logging.log4j.Logger; @AllArgsConstructor public class GeyserSpongeLogger implements GeyserLogger { diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java index a661061e2..f69a3ffb4 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java @@ -28,11 +28,12 @@ package org.geysermc.geyser.platform.sponge; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.spongepowered.api.MinecraftVersion; import org.spongepowered.api.Sponge; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.EventContext; import org.spongepowered.api.event.SpongeEventFactory; -import org.spongepowered.api.event.cause.Cause; -import org.spongepowered.api.event.cause.EventContext; import org.spongepowered.api.event.server.ClientPingServerEvent; import org.spongepowered.api.network.status.StatusClient; import org.spongepowered.api.profile.GameProfile; @@ -43,7 +44,7 @@ import java.util.Optional; public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { - private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer()); + private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.server()); private static Method SpongeStatusResponse_create; @@ -59,50 +60,46 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer); } - Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer()); + Object response = SpongeStatusResponse_create.invoke(null, Sponge.server()); event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } - Sponge.getEventManager().post(event); + Sponge.eventManager().post(event); GeyserPingInfo geyserPingInfo = new GeyserPingInfo( - event.getResponse().getDescription().toPlain(), + MessageTranslator.convertMessage(event.response().description()), new GeyserPingInfo.Players( - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(), - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline() + event.response().players().orElseThrow(IllegalStateException::new).max(), + event.response().players().orElseThrow(IllegalStateException::new).online() ), new GeyserPingInfo.Version( - event.getResponse().getVersion().getName(), + event.response().version().name(), GameProtocol.getJavaProtocolVersion()) // thanks for also not exposing this sponge ); - event.getResponse().getPlayers().get().getProfiles().stream() - .map(GameProfile::getName) - .map(op -> op.orElseThrow(IllegalStateException::new)) - .forEach(geyserPingInfo.getPlayerList()::add); + event.response().players().ifPresent(players -> players.profiles().stream() + .map(GameProfile::name) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(geyserPingInfo.getPlayerList()::add) + ); + return geyserPingInfo; } - @SuppressWarnings("NullableProblems") - private static class GeyserStatusClient implements StatusClient { - - private final InetSocketAddress remote; - - public GeyserStatusClient(InetSocketAddress remote) { - this.remote = remote; - } + private record GeyserStatusClient(InetSocketAddress remote) implements StatusClient { @Override - public InetSocketAddress getAddress() { + public InetSocketAddress address() { return this.remote; } @Override - public MinecraftVersion getVersion() { - return Sponge.getPlatform().getMinecraftVersion(); + public MinecraftVersion version() { + return Sponge.platform().minecraftVersion(); } @Override - public Optional getVirtualHost() { + public Optional virtualHost() { return Optional.empty(); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index 42040f6ab..1f9541631 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.sponge; import com.google.inject.Inject; +import org.apache.logging.log4j.Logger; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -36,18 +37,23 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager; -import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; -import org.slf4j.Logger; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; +import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.game.state.GameStartedServerEvent; -import org.spongepowered.api.event.game.state.GameStoppedEvent; -import org.spongepowered.api.plugin.Plugin; +import org.spongepowered.api.event.lifecycle.ConstructPluginEvent; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.event.lifecycle.StartedEngineEvent; +import org.spongepowered.api.event.lifecycle.StoppingEngineEvent; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; @@ -55,54 +61,134 @@ import java.nio.file.Path; import java.util.Map; import java.util.UUID; -@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Sponge", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") +@Plugin(value = "geyser") public class GeyserSpongePlugin implements GeyserBootstrap { + /** + * True if the plugin should be in a disabled state. + * This exists because you can't unregister or disable plugins in Sponge + */ + private boolean enabled = true; + + @Inject + private PluginContainer pluginContainer; + @Inject private Logger logger; @Inject @ConfigDir(sharedRoot = false) - private File configDir; + private Path configPath; - private GeyserSpongeCommandManager geyserCommandManager; + // Available after construction lifecycle private GeyserSpongeConfiguration geyserConfig; private GeyserSpongeLogger geyserLogger; + private GeyserImpl geyser; + private GeyserSpongeCommandManager geyserCommandManager; // Commands are only registered after command registration lifecycle + + // Available after StartedEngine lifecycle private IGeyserPingPassthrough geyserSpongePingPassthrough; - private GeyserImpl geyser; - public void onLoad() { + /** + * Only to be used for reloading + */ + @Override + public void onEnable() { + enabled = true; + onConstruction(null); + // new commands cannot be registered, and geyser's command manager does not need be reloaded + onStartedEngine(null); + } + + @Override + public void onDisable() { + enabled = false; + if (geyser != null) { + geyser.shutdown(); + geyser = null; + } + } + + /** + * Construct the configuration, logger, and command manager. command manager will only be filled with commands once + * the connector is started, but it allows us to register events in sponge. + * + * @param event Not used. + */ + @Listener + public void onConstruction(@Nullable ConstructPluginEvent event) { GeyserLocale.init(this); - if (!configDir.exists()) + File configDir = configPath.toFile(); + if (!configDir.exists()) { configDir.mkdirs(); + } File configFile; try { configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this); + + this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class); } catch (IOException ex) { logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed")); ex.printStackTrace(); + onDisable(); return; } - try { - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class); - } catch (IOException ex) { - logger.warn(GeyserLocale.getLocaleStringLog("geyser.config.failed")); - ex.printStackTrace(); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); + + this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); + + this.geyserCommandManager = new GeyserSpongeCommandManager(geyser); + this.geyserCommandManager.init(); + } + + /** + * Construct the {@link GeyserSpongeCommandManager} and register the commands + * + * @param event required to register the commands + */ + @Listener + public void onRegisterCommands(@Nonnull RegisterCommandEvent event) { + if (enabled) { + event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); + + for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { + Map commands = entry.getValue(); + if (commands.isEmpty()) { + continue; + } + + event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id()); + } + } + } + + /** + * Configure the config properly if remote address is auto. Start connector and ping passthrough, and register subcommands of /geyser + * + * @param event not required + */ + @Listener + public void onStartedEngine(@Nullable StartedEngineEvent event) { + if (!enabled) { return; } - if (Sponge.getServer().getBoundAddress().isPresent()) { - InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get(); + if (Sponge.server().boundAddress().isPresent()) { + InetSocketAddress javaAddr = Sponge.server().boundAddress().get(); - // Don't change the ip if its listening on all interfaces // By default this should be 127.0.0.1 but may need to be changed in some circumstances if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); + // Don't change the ip if its listening on all interfaces + if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { + this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); + } geyserConfig.getRemote().setPort(javaAddr.getPort()); } } @@ -111,14 +197,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port()); } - this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - - this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); - } - - @Override - public void onEnable() { GeyserImpl.start(); if (geyserConfig.isLegacyPingPassthrough()) { @@ -126,25 +204,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap { } else { this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough(); } - - this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser); - this.geyserCommandManager.init(); - - Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser"); - - for (Map.Entry> entry : this.geyserCommandManager.extensionCommands().entrySet()) { - Map commands = entry.getValue(); - if (commands.isEmpty()) { - continue; - } - - Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id()); - } } - @Override - public void onDisable() { - geyser.shutdown(); + @Listener + public void onEngineStopping(StoppingEngineEvent event) { + onDisable(); } @Override @@ -159,7 +223,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public GeyserCommandManager getGeyserCommandManager() { - return this.geyserCommandManager; + return geyserCommandManager; } @Override @@ -169,22 +233,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public Path getConfigFolder() { - return configDir.toPath(); - } - - @Listener - public void onServerStarting() { - onLoad(); - } - - @Listener - public void onServerStart(GameStartedServerEvent event) { - onEnable(); - } - - @Listener - public void onServerStop(GameStoppedEvent event) { - onDisable(); + return configPath; } @Override @@ -194,6 +243,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { @Override public String getMinecraftServerVersion() { - return Sponge.getPlatform().getMinecraftVersion().getName(); + return Sponge.platform().minecraftVersion().name(); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java index 3598ea8c2..a1a0d99ad 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java @@ -25,81 +25,88 @@ package org.geysermc.geyser.platform.sponge.command; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; -import org.spongepowered.api.command.CommandCallable; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.CommandCompletion; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.command.parameter.ArgumentReader; -import javax.annotation.Nullable; import java.util.*; +import java.util.stream.Collectors; -public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements CommandCallable { +public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements org.spongepowered.api.command.Command.Raw { public GeyserSpongeCommandExecutor(GeyserImpl geyser, Map commands) { super(geyser, commands); } @Override - public CommandResult process(CommandSource source, String arguments) { - GeyserCommandSource commandSender = new SpongeCommandSource(source); - GeyserSession session = getGeyserSession(commandSender); + public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) { + GeyserCommandSource commandSource = new SpongeCommandSource(cause); + GeyserSession session = getGeyserSession(commandSource); - String[] args = arguments.split(" "); - if (args.length > 0) { + String[] args = arguments.input().split(" "); + // This split operation results in an array of length 1, containing a zero length string, if the input string is empty + if (args.length > 0 && !args[0].isEmpty()) { GeyserCommand command = getCommand(args[0]); if (command != null) { - if (!source.hasPermission(command.permission())) { - // Not ideal to use log here but we dont get a session - source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); + if (!cause.hasPermission(command.permission())) { + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")).color(NamedTextColor.RED)); return CommandResult.success(); } if (command.isBedrockOnly() && session == null) { - source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only"))); + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")).color(NamedTextColor.RED)); return CommandResult.success(); } - getCommand(args[0]).execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + command.execute(session, commandSource, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + } else { + cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.not_found")).color(NamedTextColor.RED)); } } else { - getCommand("help").execute(session, commandSender, new String[0]); + getCommand("help").execute(session, commandSource, new String[0]); } return CommandResult.success(); } @Override - public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) { - if (arguments.split(" ").length == 1) { - return tabComplete(new SpongeCommandSource(source)); + public List complete(CommandCause cause, ArgumentReader.Mutable arguments) { + if (arguments.input().split(" ").length == 1) { + return tabComplete(new SpongeCommandSource(cause)).stream().map(CommandCompletion::of).collect(Collectors.toList()); } return Collections.emptyList(); } @Override - public boolean testPermission(CommandSource source) { + public boolean canExecute(CommandCause cause) { return true; } @Override - public Optional getShortDescription(CommandSource source) { - return Optional.of(Text.of("The main command for Geyser.")); + public Optional shortDescription(CommandCause cause) { + return Optional.of(Component.text("The main command for Geyser.")); } @Override - public Optional getHelp(CommandSource source) { - return Optional.of(Text.of("/geyser help")); + public Optional extendedDescription(CommandCause cause) { + return shortDescription(cause); } @Override - public Text getUsage(CommandSource source) { - return Text.of("/geyser help"); + public Optional help(@NotNull CommandCause cause) { + return Optional.of(Component.text("/geyser help")); + } + + @Override + public Component usage(CommandCause cause) { + return Component.text("/geyser help"); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java index 8e981f72a..d83e3a723 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java @@ -25,25 +25,37 @@ package org.geysermc.geyser.platform.sponge.command; +import net.kyori.adventure.text.Component; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.translator.text.MessageTranslator; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.manager.CommandMapping; + +import java.util.Optional; public class GeyserSpongeCommandManager extends GeyserCommandManager { - private final org.spongepowered.api.command.CommandManager handle; - public GeyserSpongeCommandManager(org.spongepowered.api.command.CommandManager handle, GeyserImpl geyser) { + public GeyserSpongeCommandManager(GeyserImpl geyser) { super(geyser); - - this.handle = handle; } @Override public String description(String command) { - return handle.get(command).map(CommandMapping::getCallable) - .map(callable -> callable.getShortDescription(Sponge.getServer().getConsole()).orElse(Text.EMPTY)) - .orElse(Text.EMPTY).toPlain(); + if (!Sponge.isServerAvailable()) { + return ""; + } + + // Note: The command manager may be replaced at any point during the game lifecycle + return Sponge.server().commandManager().commandMapping(command) + .map(this::description) + .map(Optional::get) + .map(MessageTranslator::convertMessage) + .orElse(""); + } + + public Optional description(CommandMapping mapping) { + return mapping.registrar().shortDescription(CommandCause.create(), mapping); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java index 12fdcb989..31dccc1fb 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSource.java @@ -26,29 +26,30 @@ package org.geysermc.geyser.platform.sponge.command; import lombok.AllArgsConstructor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.command.GeyserCommandSource; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.source.ConsoleSource; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; @AllArgsConstructor public class SpongeCommandSource implements GeyserCommandSource { - private CommandSource handle; + private final CommandCause handle; @Override public String name() { - return handle.getName(); + return handle.friendlyIdentifier().orElse(handle.identifier()); } @Override - public void sendMessage(String message) { - handle.sendMessage(Text.of(message)); + public void sendMessage(@NonNull String message) { + handle.audience().sendMessage(LegacyComponentSerializer.legacySection().deserialize(message)); } @Override public boolean isConsole() { - return handle instanceof ConsoleSource; + return !(handle.cause().root() instanceof ServerPlayer); } @Override diff --git a/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json b/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json new file mode 100644 index 000000000..2540f87b7 --- /dev/null +++ b/bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json @@ -0,0 +1,30 @@ +{ + "loader": { + "name": "java_plain", + "version": "1.0" + }, + "license": "MIT", + "plugins": [ + { + "id": "${id}", + "name": "${name}-Sponge", + "version": "${version}", + "entrypoint": "org.geysermc.geyser.platform.sponge.GeyserSpongePlugin", + "description": "${description}", + "links": { + "homepage": "${url}" + }, + "contributors": [ + { + "name": "${author}" + } + ], + "dependencies": [ + { + "id": "spongeapi", + "version": "8.0.0" + } + ] + } + ] +} diff --git a/bootstrap/sponge/src/main/resources/pack.mcmeta b/bootstrap/sponge/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..19e8dca71 --- /dev/null +++ b/bootstrap/sponge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "Geyser for Sponge", + "pack_format": 6 + } +} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java index 9f429cc83..b2765d3b2 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java @@ -51,8 +51,9 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo { this.platformVersion = proxy.getVersion().getVersion(); this.platformVendor = proxy.getVersion().getVendor(); this.onlineMode = proxy.getConfiguration().isOnlineMode(); - if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) { - this.serverIP = proxy.getBoundAddress().getHostString(); + String hostString = proxy.getBoundAddress().getHostString(); + if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0"))) { + this.serverIP = hostString; } else { this.serverIP = "***"; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java index c77a3daef..c89c35b06 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java @@ -63,6 +63,9 @@ public class GeyserVelocityCommandExecutor extends GeyserCommandExecutor impleme return; } command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]); + } else { + String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", sender.locale()); + sender.sendMessage(ChatColor.RED + message); } } else { getCommand("help").execute(session, sender, new String[0]); diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index ac652764b..9414655bc 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -9,7 +9,7 @@ dependencies { tasks { processResources { - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) { + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json")) { expand( "id" to "Geyser", "name" to "Geyser", diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 51d6f5ba7..a9cf5999a 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 51d6f5ba7d85bfda318879dad34481d9ef4d488d +Subproject commit a9cf5999af605902b18dd5c77d3562481f8d7f3d diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 2c68dab9d..f1c9c2fbb 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 2c68dab9d751f78b2f5b0298da5e338ad6bc07ca +Subproject commit f1c9c2fbba0e102dc4f8c96dd9485f7ec9768174 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5f9d72d57..28b687f9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ adapters = "1.5-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.0.0" -sponge = "7.1.0" +sponge = "8.0.0" [libraries] jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } From fc25592df60030667fae60e501559fc45b2b21b9 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 2 Oct 2022 18:25:49 -0400 Subject: [PATCH 209/290] Changed the id in resource processing to be lowercase (#3329) --- .../src/main/kotlin/geyser.base-conventions.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 9414655bc..bd50c6ea0 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -11,7 +11,7 @@ tasks { processResources { filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json")) { expand( - "id" to "Geyser", + "id" to "geyser", "name" to "Geyser", "version" to project.version, "description" to project.description, @@ -30,4 +30,4 @@ java { targetCompatibility = JavaVersion.VERSION_16 withSourcesJar() -} \ No newline at end of file +} From 82249763936f403ae90a06ef8c66297ceabd3dd5 Mon Sep 17 00:00:00 2001 From: Luke Chambers Date: Mon, 3 Oct 2022 10:37:22 -0400 Subject: [PATCH 210/290] Publish entire java component and common (#3331) --- .../src/main/kotlin/geyser.publish-conventions.gradle.kts | 5 ++--- common/build.gradle.kts | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts index 68ab59337..7525f97fa 100644 --- a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts @@ -11,8 +11,7 @@ publishing { artifactId = project.name version = project.version as String - artifact(tasks["shadowJar"]) - artifact(tasks["sourcesJar"]) + from(components["java"]) } } } @@ -31,4 +30,4 @@ artifactory { setPublishIvy(false) } } -} \ No newline at end of file +} diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 44f97b9fa..db3fe3a77 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,4 +1,8 @@ +plugins { + id("geyser.publish-conventions") +} + dependencies { api(libs.cumulus) api(libs.gson) -} \ No newline at end of file +} From 7f05ab9d223a53ea45697458725296ad5dbb4bda Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 3 Oct 2022 13:15:30 -0400 Subject: [PATCH 211/290] Fix reloading on Spigot Fixes #3319 --- .../platform/spigot/GeyserSpigotPlugin.java | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 65de068af..d7a4da7c8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -196,36 +196,43 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.loadFloodgate(this); - // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes - Bukkit.getPluginManager().registerEvents(new Listener() { + if (!INITIALIZED) { + // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes + Bukkit.getPluginManager().registerEvents(new Listener() { - @EventHandler - public void onServerLoaded(ServerLoadEvent event) { - // Wait until all plugins have loaded so Geyser can start - postStartup(); + @EventHandler + public void onServerLoaded(ServerLoadEvent event) { + // Wait until all plugins have loaded so Geyser can start + postStartup(); + } + }, this); + + this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); + this.geyserCommandManager.init(); + + // Because Bukkit locks its command map upon startup, we need to + // add our plugin commands in onEnable, but populating the executor + // can happen at any time + CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); + for (Extension extension : this.geyserCommandManager.extensionCommands().keySet()) { + // Thanks again, Bukkit + try { + Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + constructor.setAccessible(true); + + PluginCommand pluginCommand = constructor.newInstance(extension.description().id(), this); + pluginCommand.setDescription("The main command for the " + extension.name() + " Geyser extension!"); + + commandMap.register(extension.description().id(), "geyserext", pluginCommand); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { + this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex); + } } - }, this); + } - this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); - this.geyserCommandManager.init(); - - // Because Bukkit locks its command map upon startup, we need to - // add our plugin commands in onEnable, but populating the executor - // can happen at any time - CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap(); - for (Extension extension : this.geyserCommandManager.extensionCommands().keySet()) { - // Thanks again, Bukkit - try { - Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); - constructor.setAccessible(true); - - PluginCommand pluginCommand = constructor.newInstance(extension.description().id(), this); - pluginCommand.setDescription("The main command for the " + extension.name() + " Geyser extension!"); - - commandMap.register(extension.description().id(), "geyserext", pluginCommand); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { - this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex); - } + if (INITIALIZED) { + // Reload; continue with post startup + postStartup(); } } From 07c7b2f7f8166fd1adde6551c2e1ab7cbc0c2501 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 3 Oct 2022 13:33:24 -0400 Subject: [PATCH 212/290] Clean up on legacy code that will no longer trigger --- .../platform/spigot/GeyserSpigotPlugin.java | 30 +---- .../spigot/command/SpigotCommandSource.java | 61 +-------- .../spigot/world/GeyserPistonListener.java | 7 +- .../GeyserSpigot1_12NativeWorldManager.java | 61 --------- .../manager/GeyserSpigot1_12WorldManager.java | 125 ------------------ .../GeyserSpigotFallbackWorldManager.java | 56 -------- .../manager/GeyserSpigotWorldManager.java | 13 +- 7 files changed, 13 insertions(+), 340 deletions(-) delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java delete mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index d7a4da7c8..5f0061382 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -60,7 +60,6 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; -import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.geyser.platform.spigot.world.manager.*; @@ -269,14 +268,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } } } - // Used to determine if Block.getBlockData() is present. - boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0"); - if (isLegacy) - geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected; falling back to ViaVersion for block state retrieval."); - - boolean isPre1_12 = !isCompatible(Bukkit.getServer().getVersion(), "1.12.0"); - // Set if we need to use a different method for getting a player's locale - SpigotCommandSource.setUseLegacyLocaleMethod(isPre1_12); // We want to do this late in the server startup process to allow plugins such as ViaVersion and ProtocolLib // To do their job injecting, then connect into *that* @@ -289,13 +280,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { String nmsVersion = name.substring(name.lastIndexOf('.') + 1); SpigotAdapters.registerWorldAdapter(nmsVersion); if (isViaVersion && isViaVersionNeeded()) { - if (isLegacy) { - // Pre-1.13 - this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(this); - } else { - // Post-1.13 - this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this); - } + this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this); } else { // No ViaVersion this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this); @@ -312,17 +297,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } if (this.geyserWorldManager == null) { // No NMS adapter - if (isLegacy && isViaVersion) { - // Use ViaVersion for converting pre-1.13 block states - this.geyserWorldManager = new GeyserSpigot1_12WorldManager(this); - } else if (isLegacy) { - // Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air - this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(this); - } else { - // Post-1.13 - this.geyserWorldManager = new GeyserSpigotWorldManager(this); - } - geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); + this.geyserWorldManager = new GeyserSpigotWorldManager(this); + geyserLogger.debug("Using default world manager."); } PluginCommand geyserCommand = this.getCommand("geyser"); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java index 8deddd8e6..95fba707f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSource.java @@ -29,31 +29,17 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.platform.spigot.PaperAdventure; import org.geysermc.geyser.text.GeyserLocale; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - public class SpigotCommandSource implements GeyserCommandSource { - - /** - * Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version. - * 1.12 or greater should not use the legacy method. - */ - private static boolean USE_LEGACY_METHOD = false; - private static Method LOCALE_METHOD; - private final org.bukkit.command.CommandSender handle; - private final String locale; public SpigotCommandSource(org.bukkit.command.CommandSender handle) { this.handle = handle; - this.locale = getSpigotLocale(); // Ensure even Java players' languages are loaded - GeyserLocale.loadGeyserLocale(locale); + GeyserLocale.loadGeyserLocale(locale()); } @Override @@ -84,50 +70,15 @@ public class SpigotCommandSource implements GeyserCommandSource { @Override public String locale() { - return locale; + if (this.handle instanceof Player player) { + return player.getLocale(); + } + + return GeyserLocale.getDefaultLocale(); } @Override public boolean hasPermission(String permission) { return handle.hasPermission(permission); } - - /** - * Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get - * {@code player.spigot().getLocale()}. - * - * @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale - */ - public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) { - USE_LEGACY_METHOD = useLegacyMethod; - if (USE_LEGACY_METHOD) { - try { - //noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it - LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale"); - } catch (NoSuchMethodException e) { - GeyserImpl.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!"); - } - } - } - - /** - * So we only have to do nasty reflection stuff once per command - * - * @return the locale of the Spigot player - */ - private String getSpigotLocale() { - if (handle instanceof Player player) { - if (USE_LEGACY_METHOD) { - try { - // sigh - // This was the only option on older Spigot instances and now it's gone - return (String) LOCALE_METHOD.invoke(player.spigot()); - } catch (IllegalAccessException | InvocationTargetException ignored) { - } - } else { - return player.getLocale(); - } - } - return GeyserLocale.getDefaultLocale(); - } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 8be1cb84e..5eb99e10c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -105,13 +105,10 @@ public class GeyserPistonListener implements Listener { // Trying to grab the blocks from the world like other platforms would result in the moving piston block // being returned instead. if (!blocksFilled) { - // Blocks currently require a player for 1.12, so let's just leech off one player to get all blocks - // and call it a day for the rest of the sessions (mostly to save on execution time) List blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks(); for (Block block : blocks) { Location attachedLocation = block.getLocation(); - int blockId = worldManager.getBlockNetworkId(player, block, - attachedLocation.getBlockX(), attachedLocation.getBlockY(), attachedLocation.getBlockZ()); + int blockId = worldManager.getBlockNetworkId(block); // Ignore blocks that will be destroyed if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) { attachedBlocks.put(getVector(attachedLocation), blockId); @@ -120,7 +117,7 @@ public class GeyserPistonListener implements Listener { blocksFilled = true; } - int pistonBlockId = worldManager.getBlockNetworkId(player, event.getBlock(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); + int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock()); // event.getDirection() is unreliable Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java deleted file mode 100644 index 0ac8d6856..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.spigot.world.manager; - -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.geysermc.geyser.adapters.spigot.SpigotAdapters; -import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.session.GeyserSession; - -/** - * Used with ViaVersion and pre-1.13. - */ -public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager { - private final SpigotWorldAdapter adapter; - - public GeyserSpigot1_12NativeWorldManager(Plugin plugin) { - super(plugin); - this.adapter = SpigotAdapters.getWorldAdapter(); - // Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return BlockStateValues.JAVA_AIR_ID; - } - // Get block entity storage - BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class); - int blockId = adapter.getBlockAt(player.getWorld(), x, y, z); - return getLegacyBlock(storage, blockId, x, y, z); - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java deleted file mode 100644 index 2ca024abf..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.spigot.world.manager; - -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.data.MappingData; -import com.viaversion.viaversion.api.minecraft.Position; -import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage; -import org.bukkit.Bukkit; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.session.GeyserSession; - -import java.util.List; - -/** - * Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13. - * - * You need ViaVersion to connect to an older server with the Geyser-Spigot plugin. - */ -public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager { - /** - * Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state. - * (Block IDs did not change between server versions until 1.13 and after) - */ - private final MappingData mappingData1_12to1_13; - - /** - * The list of all protocols from the client's version to 1.13. - */ - private final List protocolList; - - public GeyserSpigot1_12WorldManager(Plugin plugin) { - super(plugin); - this.mappingData1_12to1_13 = Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getMappingData(); - this.protocolList = Via.getManager().getProtocolManager().getProtocolPath(CLIENT_PROTOCOL_VERSION, - ProtocolVersion.v1_13.getVersion()); - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return BlockStateValues.JAVA_AIR_ID; - } - if (!player.getWorld().isChunkLoaded(x >> 4, z >> 4)) { - // Prevent nasty async errors if a player is loading in - return BlockStateValues.JAVA_AIR_ID; - } - - Block block = player.getWorld().getBlockAt(x, y, z); - return getBlockNetworkId(player, block, x, y, z); - } - - @Override - @SuppressWarnings("deprecation") - public int getBlockNetworkId(Player player, Block block, int x, int y, int z) { - // Get block entity storage - BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class); - // Black magic that gets the old block state ID - int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF); - return getLegacyBlock(storage, oldBlockId, x, y, z); - } - - /** - * - * @param storage ViaVersion's block entity storage (used to fix block entity state differences) - * @param blockId the pre-1.13 block id - * @param x X coordinate of block - * @param y Y coordinate of block - * @param z Z coordinate of block - * @return the block state updated to the latest Minecraft version - */ - public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) { - // Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2 - blockId = mappingData1_12to1_13.getNewBlockId(blockId); - // Translate block entity differences - some information was stored in block tags and not block states - if (storage.isWelcome(blockId)) { // No getOrDefault method - BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z)); - if (data != null && data.getReplacement() != -1) { - blockId = data.getReplacement(); - } - } - for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getProtocol().getMappingData(); - if (mappingData != null) { - blockId = mappingData.getNewBlockStateId(blockId); - } - } - return blockId; - } - - @Override - public boolean isLegacy() { - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java deleted file mode 100644 index fa78a671c..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.spigot.world.manager; - -import org.bukkit.plugin.Plugin; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.session.GeyserSession; - -/** - * Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)} - * cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect. - * If this occurs to you somehow, please let us know!! - */ -public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager { - public GeyserSpigotFallbackWorldManager(Plugin plugin) { - super(plugin); - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - return BlockStateValues.JAVA_AIR_ID; - } - - @Override - public boolean hasOwnChunkCache() { - return false; - } - - @Override - public boolean isLegacy() { - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 093e28794..7bb8f1666 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -33,7 +33,6 @@ import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Lectern; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; @@ -41,7 +40,6 @@ import org.bukkit.plugin.Plugin; import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; @@ -54,11 +52,6 @@ import java.util.List; * The base world manager to use when there is no supported NMS revision */ public class GeyserSpigotWorldManager extends GeyserWorldManager { - /** - * The current client protocol version for ViaVersion usage. - */ - protected static final int CLIENT_PROTOCOL_VERSION = GameProtocol.getJavaProtocolVersion(); - private final Plugin plugin; public GeyserSpigotWorldManager(Plugin plugin) { @@ -77,10 +70,10 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { return BlockStateValues.JAVA_AIR_ID; } - return getBlockNetworkId(bukkitPlayer, world.getBlockAt(x, y, z), x, y, z); + return getBlockNetworkId(world.getBlockAt(x, y, z)); } - public int getBlockNetworkId(Player player, Block block, int x, int y, int z) { + public int getBlockNetworkId(Block block) { return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); } @@ -181,8 +174,6 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { } /** - * This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}. - * * This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id * to the current one. * From 7edde43141c727302dcf4a1e357e7e294e2ced30 Mon Sep 17 00:00:00 2001 From: SupremeMortal <6178101+SupremeMortal@users.noreply.github.com> Date: Mon, 3 Oct 2022 21:11:07 +0100 Subject: [PATCH 213/290] Initial fabric merger --- bootstrap/fabric/.gitignore | 240 ------------------ bootstrap/fabric/.idea/copyright/Geyser.xml | 6 - .../.idea/copyright/profiles_settings.xml | 7 - bootstrap/fabric/Jenkinsfile | 105 -------- bootstrap/fabric/LICENSE | 21 -- bootstrap/fabric/README.md | 10 - bootstrap/fabric/build.gradle | 120 --------- bootstrap/fabric/build.gradle.kts | 95 +++++++ bootstrap/fabric/gradle.properties | 14 - .../fabric/gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - bootstrap/fabric/gradlew | 234 ----------------- bootstrap/fabric/gradlew.bat | 89 ------- bootstrap/fabric/settings.gradle | 10 - bootstrap/spigot/build.gradle.kts | 7 +- build-logic/build.gradle.kts | 11 +- gradle.properties | 20 +- gradle/libs.versions.toml | 1 + settings.gradle.kts | 5 +- 19 files changed, 130 insertions(+), 870 deletions(-) delete mode 100644 bootstrap/fabric/.gitignore delete mode 100644 bootstrap/fabric/.idea/copyright/Geyser.xml delete mode 100644 bootstrap/fabric/.idea/copyright/profiles_settings.xml delete mode 100644 bootstrap/fabric/Jenkinsfile delete mode 100644 bootstrap/fabric/LICENSE delete mode 100644 bootstrap/fabric/README.md delete mode 100644 bootstrap/fabric/build.gradle create mode 100644 bootstrap/fabric/build.gradle.kts delete mode 100644 bootstrap/fabric/gradle.properties delete mode 100644 bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar delete mode 100644 bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties delete mode 100755 bootstrap/fabric/gradlew delete mode 100644 bootstrap/fabric/gradlew.bat delete mode 100644 bootstrap/fabric/settings.gradle diff --git a/bootstrap/fabric/.gitignore b/bootstrap/fabric/.gitignore deleted file mode 100644 index 06b9cccc4..000000000 --- a/bootstrap/fabric/.gitignore +++ /dev/null @@ -1,240 +0,0 @@ - -# 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/ - -# 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/ \ No newline at end of file diff --git a/bootstrap/fabric/.idea/copyright/Geyser.xml b/bootstrap/fabric/.idea/copyright/Geyser.xml deleted file mode 100644 index bdffbbbd6..000000000 --- a/bootstrap/fabric/.idea/copyright/Geyser.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/bootstrap/fabric/.idea/copyright/profiles_settings.xml b/bootstrap/fabric/.idea/copyright/profiles_settings.xml deleted file mode 100644 index f2d5911c9..000000000 --- a/bootstrap/fabric/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/bootstrap/fabric/Jenkinsfile b/bootstrap/fabric/Jenkinsfile deleted file mode 100644 index c3632a8ce..000000000 --- a/bootstrap/fabric/Jenkinsfile +++ /dev/null @@ -1,105 +0,0 @@ -pipeline { - agent any - tools { - gradle 'Gradle 7' - jdk 'Java 17' - } - - parameters { - booleanParam(defaultValue: false, description: 'Skip Discord notification', name: 'SKIP_DISCORD') - } - - options { - buildDiscarder(logRotator(artifactNumToKeepStr: '20')) - } - - stages { - stage ('Build') { - steps { - sh './gradlew clean build --refresh-dependencies' - } - post { - success { - archiveArtifacts artifacts: 'build/libs/*.jar', excludes: 'build/libs/Geyser-Fabric-*-sources*.jar,build/libs/Geyser-Fabric-*-all*.jar', fingerprint: true - } - } - } - - stage ('Deploy') { - when { - anyOf { - branch "java-1.18" - } - } - - steps { - rtGradleDeployer( - id: "GRADLE_DEPLOYER", - serverId: "opencollab-artifactory", - releaseRepo: "maven-releases", - snapshotRepo: "maven-snapshots" - ) - rtGradleResolver( - id: "GRADLE_RESOLVER", - serverId: "opencollab-artifactory" - ) - rtGradleRun ( - usesPlugin: false, - tool: 'Gradle 7', - rootDir: "", - buildFile: 'build.gradle', - tasks: 'build artifactoryPublish', - deployerId: "GRADLE_DEPLOYER", - resolverId: "GRADLE_RESOLVER" - ) - rtPublishBuildInfo( - serverId: "opencollab-artifactory" - ) - } - } - } - - 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() - 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 - } - } - } - } - } -} diff --git a/bootstrap/fabric/LICENSE b/bootstrap/fabric/LICENSE deleted file mode 100644 index d8ee99620..000000000 --- a/bootstrap/fabric/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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/README.md b/bootstrap/fabric/README.md deleted file mode 100644 index 883d03289..000000000 --- a/bootstrap/fabric/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Geyser-Fabric - -[![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/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/) - -Geyser-Fabric is Geyser specifically built for the Fabric modding platform. For more details, see [here](https://github.com/GeyserMC/Geyser/wiki/Geyser-Fabric). diff --git a/bootstrap/fabric/build.gradle b/bootstrap/fabric/build.gradle deleted file mode 100644 index 2ea9fd686..000000000 --- a/bootstrap/fabric/build.gradle +++ /dev/null @@ -1,120 +0,0 @@ -plugins { - id 'fabric-loom' version '0.12-SNAPSHOT' - id 'maven-publish' - id 'com.github.johnrengelman.shadow' version '7.0.0' - id 'java' -} - -apply plugin: 'com.github.johnrengelman.shadow' -apply plugin: 'java' - -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -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. - - 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' - exclude group: 'com.nukkitx.fastutil' - exclude group: 'io.netty.incubator' - } -} - -repositories { - mavenLocal() - - maven { - url = uri('https://repo.opencollab.dev/maven-releases/') - } - - maven { - url = uri('https://repo.opencollab.dev/maven-snapshots/') - } - - maven { - url = uri('https://jitpack.io') - } - - maven { - url = uri('https://oss.sonatype.org/content/repositories/snapshots/') - } -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -// 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 -} - -shadowJar { - configurations = [project.configurations.shadow] - 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 "LICENSE" -} - -remapJar { - dependsOn(shadowJar) - input = tasks.shadowJar.archiveFile - archiveName = "Geyser-Fabric.jar" -} - -// 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/build.gradle.kts b/bootstrap/fabric/build.gradle.kts new file mode 100644 index 000000000..ef526aa00 --- /dev/null +++ b/bootstrap/fabric/build.gradle.kts @@ -0,0 +1,95 @@ +plugins { + id("fabric-loom") version "0.12-SNAPSHOT" + id("maven-publish") + id("com.github.johnrengelman.shadow") + id("java") +} + +java { + targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_17 +} + +//archivesBaseName = project.archives_base_name +//version = project.mod_version +//group = project.maven_group + +val minecraftVersion = project.property("minecraft_version") as String +val yarnVersion = project.property("yarn_mappings") as String +val loaderVersion = project.property("loader_version") as String +val fabricVersion = project.property("fabric_version") as String + +dependencies { + //to change the versions see the gradle.properties file + minecraft("com.mojang:minecraft:$minecraftVersion") + mappings("net.fabricmc:yarn:$yarnVersion:v2") + modImplementation("net.fabricmc:fabric-loader:$loaderVersion") + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. + // You may need to force-disable transitiveness on them. + + api(projects.core) + shadow(projects.core) { + exclude(group = "com.google.guava", module = "guava") + exclude(group = "com.google.code.gson", module = "gson") + exclude(group = "org.slf4j") + exclude(group = "com.nukkitx.fastutil") + exclude(group = "io.netty.incubator") + } +} + +repositories { + mavenLocal() + maven("https://repo.opencollab.dev/maven-releases/") + maven("https://repo.opencollab.dev/maven-snapshots/") + maven("https://jitpack.io") + maven("https://oss.sonatype.org/content/repositories/snapshots/") + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") +} + +tasks { + processResources { +// inputs.property "version", project.version +// +// filesMatching("fabric.mod.json") { +// expand "version": project.version +// } + } + + // 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 + compileJava { + 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. + sourcesJar { + archiveClassifier.set("sources") + from(sourceSets.main.get().allSource) + } + + 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("LICENSE") + } + + remapJar { + dependsOn(shadowJar) + inputs.file(shadowJar.get().archiveFile) + archiveBaseName.set("Geyser-Fabric") + archiveClassifier.set("") + archiveVersion.set("") + } +} \ No newline at end of file diff --git a/bootstrap/fabric/gradle.properties b/bootstrap/fabric/gradle.properties deleted file mode 100644 index 341d6bbe4..000000000 --- a/bootstrap/fabric/gradle.properties +++ /dev/null @@ -1,14 +0,0 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx2G -# Fabric Properties -# check these on https://modmuss50.me/fabric.html -minecraft_version=1.19.1 -yarn_mappings=1.19.1+build.1 -loader_version=0.14.8 -# Mod Properties -mod_version=2.1.0-SNAPSHOT -maven_group=org.geysermc.platform -archives_base_name=Geyser-Fabric -# Dependencies -# check this on https://modmuss50.me/fabric.html -fabric_version=0.58.5+1.19.1 diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties b/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e750102e0..000000000 --- a/bootstrap/fabric/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/bootstrap/fabric/gradlew b/bootstrap/fabric/gradlew deleted file mode 100755 index 1b6c78733..000000000 --- a/bootstrap/fabric/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original 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 POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -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 - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -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 - -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 ;; #( - MSYS* | 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" && ! "$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 - -# 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. - -# 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 deleted file mode 100644 index ac1b06f93..000000000 --- a/bootstrap/fabric/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@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 execute - -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 execute - -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 - -: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 %* - -: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 deleted file mode 100644 index 5b60df3d2..000000000 --- a/bootstrap/fabric/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -pluginManagement { - repositories { - jcenter() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - gradlePluginPortal() - } -} diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index 31e68ed92..b5ef4e69e 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -1,8 +1,3 @@ -val paperVersion = "1.19-R0.1-SNAPSHOT" -val viaVersion = "4.0.0" -val adaptersVersion = "1.5-SNAPSHOT" -val commodoreVersion = "2.2" - dependencies { api(projects.core) @@ -34,7 +29,7 @@ platformRelocate("me.lucko.commodore") platformRelocate("io.netty.channel.kqueue") // These dependencies are already present on the platform -provided("com.viaversion", "viaversion", viaVersion) +provided(libs.viaversion) application { mainClass.set("org.geysermc.geyser.platform.spigot.GeyserSpigotMain") diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 25cbfe9de..6f4647c0f 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -11,7 +11,16 @@ repositories { dependencies { implementation("net.kyori", "indra-common", "2.0.6") implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1") - implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1") + implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.2") { + exclude("org.ow2.asm", "*") + } + + // Within the gradle plugin classpath, there is a version conflict between loom and some other + // plugin for databind. This fixes it: minimum 2.13.2 is required by loom. + implementation("com.fasterxml.jackson.core:jackson-databind:2.13.3") + + // Use a newer version of ObjectWeb ASM than the one provided by loom. + implementation("org.ow2.asm:asm-commons:9.4") } tasks.withType { diff --git a/gradle.properties b/gradle.properties index 8f6ac8e85..35cb21537 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,24 @@ +# Gradle settings +org.gradle.jvmargs=-Xmx4G +org.gradle.configureondemand=true +org.gradle.caching=true +org.gradle.parallel=true + group=org.geysermc version=2.1.0-SNAPSHOT org.gradle.caching=true org.gradle.parallel=true -org.gradle.vfs.watch=false \ No newline at end of file +org.gradle.vfs.watch=false + +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version=1.19.1 +yarn_mappings=1.19.1+build.1 +loader_version=0.14.8 +# Mod Properties +maven_group=org.geysermc.platform +archives_base_name=Geyser-Fabric +# Dependencies +# check this on https://modmuss50.me/fabric.html +fabric_version=0.58.5+1.19.1 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 28b687f9b..bf4688d7f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -79,6 +79,7 @@ raknet = { group = "com.nukkitx.network", name = "raknet", version.ref = "raknet sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } +viaversion = { group = "com.viaversion", name = "viaversion", version.ref = "viaversion" } websocket = { group = "org.java-websocket", name = "Java-WebSocket", version.ref = "websocket" } [bundles] diff --git a/settings.gradle.kts b/settings.gradle.kts index f6d13ad0d..b61fefc31 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) +// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { // Floodgate, Cumulus etc. maven("https://repo.opencollab.dev/main") @@ -47,6 +47,7 @@ dependencyResolutionManagement { pluginManagement { repositories { gradlePluginPortal() + maven("https://maven.fabricmc.net/") } plugins { id("net.kyori.blossom") version "1.2.0" @@ -62,6 +63,7 @@ include(":ap") include(":api") include(":geyser-api") include(":bungeecord") +include(":fabric") include(":spigot") include(":sponge") include(":standalone") @@ -73,6 +75,7 @@ include(":core") project(":api").projectDir = file("api/base") project(":geyser-api").projectDir = file("api/geyser") project(":bungeecord").projectDir = file("bootstrap/bungeecord") +project(":fabric").projectDir = file("bootstrap/fabric") project(":spigot").projectDir = file("bootstrap/spigot") project(":sponge").projectDir = file("bootstrap/sponge") project(":standalone").projectDir = file("bootstrap/standalone") From 97ec5fec3357e317a118708cab5e866e2ab79bf4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 3 Oct 2022 18:27:42 -0400 Subject: [PATCH 214/290] Force-disable query if it would interfere with Geyser's startup. Fixes #3312 --- .../bungeecord/GeyserBungeePlugin.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index d6b252473..ab5531ba3 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -137,6 +137,24 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } } + // Force-disable query if enabled, or else Geyser won't enable + for (ListenerInfo info : getProxy().getConfig().getListeners()) { + if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) { + try { + Field queryField = ListenerInfo.class.getDeclaredField("queryEnabled"); + queryField.setAccessible(true); + queryField.setBoolean(info, false); + geyserLogger.warning("We force-disabled query on port " + info.getQueryPort() + " in order for Geyser to boot up successfully. " + + "To remove this message, disable query in your proxy's config."); + } catch (NoSuchFieldException | IllegalAccessException e) { + geyserLogger.warning("Could not force-disable query. Geyser may not start correctly!"); + if (geyserLogger.isDebug()) { + e.printStackTrace(); + } + } + } + } + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); return; From 5a805bc688f564a0dad8f35913903f257706b362 Mon Sep 17 00:00:00 2001 From: SupremeMortal <6178101+SupremeMortal@users.noreply.github.com> Date: Tue, 4 Oct 2022 23:18:53 +0100 Subject: [PATCH 215/290] Fix building --- bootstrap/fabric/build.gradle.kts | 5 +++-- build-logic/build.gradle.kts | 8 ++------ settings.gradle.kts | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index ef526aa00..5c2409be8 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("fabric-loom") version "0.12-SNAPSHOT" + id("fabric-loom") version "1.0-SNAPSHOT" id("maven-publish") id("com.github.johnrengelman.shadow") id("java") @@ -79,6 +79,7 @@ tasks { 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") + archiveClassifier.set("unshaded") // We don't want it included in the archived artifacts } jar { @@ -87,7 +88,7 @@ tasks { remapJar { dependsOn(shadowJar) - inputs.file(shadowJar.get().archiveFile) + inputFile.set(shadowJar.get().archiveFile) archiveBaseName.set("Geyser-Fabric") archiveClassifier.set("") archiveVersion.set("") diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 6f4647c0f..c992a3ca9 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -6,21 +6,17 @@ plugins { repositories { gradlePluginPortal() + maven("https://repo.opencollab.dev/maven-snapshots") } dependencies { implementation("net.kyori", "indra-common", "2.0.6") implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1") - implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.2") { - exclude("org.ow2.asm", "*") - } + implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT") // Within the gradle plugin classpath, there is a version conflict between loom and some other // plugin for databind. This fixes it: minimum 2.13.2 is required by loom. implementation("com.fasterxml.jackson.core:jackson-databind:2.13.3") - - // Use a newer version of ObjectWeb ASM than the one provided by loom. - implementation("org.ow2.asm:asm-commons:9.4") } tasks.withType { diff --git a/settings.gradle.kts b/settings.gradle.kts index b61fefc31..6f212d3ac 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -48,6 +48,7 @@ pluginManagement { repositories { gradlePluginPortal() maven("https://maven.fabricmc.net/") + maven("https://repo.opencollab.dev/maven-snapshots") } plugins { id("net.kyori.blossom") version "1.2.0" From f4b810534b28027a9f828444ba14bb28776bdd18 Mon Sep 17 00:00:00 2001 From: Jens Collaert <63231928+Jens-Co@users.noreply.github.com> Date: Fri, 7 Oct 2022 19:14:42 +0200 Subject: [PATCH 216/290] Remove Windows version number from UWP. (#3339) --- .../src/main/java/org/geysermc/api/util/BedrockPlatform.java | 2 +- common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java index e486f73bc..15d0da027 100644 --- a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java +++ b/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java @@ -35,7 +35,7 @@ public enum BedrockPlatform { AMAZON("Amazon"), GEARVR("Gear VR"), HOLOLENS("Hololens"), - UWP("Windows 10"), + UWP("Windows"), WIN32("Windows x86"), DEDICATED("Dedicated"), TVOS("Apple TV"), diff --git a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java index ef7709859..406204759 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java +++ b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java @@ -40,7 +40,7 @@ public enum DeviceOs { AMAZON("Amazon"), GEARVR("Gear VR"), HOLOLENS("Hololens"), - UWP("Windows 10"), + UWP("Windows"), WIN32("Windows x86"), DEDICATED("Dedicated"), TVOS("Apple TV"), From f59e33d749c7e8fa3df69dc004e795a8ed4c7230 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 10 Oct 2022 15:40:07 -0400 Subject: [PATCH 217/290] Fix behavior of matching custom item predicates Huge thanks to Kastle for helping me disect this behavior. - The Unbreakable NBT tag is not the only source for determining if an item should be treated as unbreakable. The damage NBT is also taken into account. - Custom item options must be processed in an ascending order. - Multiple conditions may be necessary for an item to be selected. - Conditions do not have to be exact. See the comments in CustomItemTranslator for an explanation. - Added a test so we don't break this behavior in the future. --- .../CustomItemRegistryPopulator.java | 4 +- .../populator/ItemRegistryPopulator.java | 20 +- .../geyser/registry/type/ItemMapping.java | 15 +- .../geysermc/geyser/text/GeyserLocale.java | 22 +++ .../inventory/item/CustomItemTranslator.java | 105 +++++++++++ .../inventory/item/ItemTranslator.java | 171 +++--------------- .../inventory/item/CustomItemsTest.java | 116 ++++++++++++ 7 files changed, 293 insertions(+), 160 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java create mode 100644 core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 64543272e..017ede61e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -30,7 +30,6 @@ import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import it.unimi.dsi.fastutil.objects.Object2IntMaps; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; @@ -43,6 +42,7 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; import javax.annotation.Nullable; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.OptionalInt; @@ -85,7 +85,7 @@ public class CustomItemRegistryPopulator { .maxDamage(customItemData.maxDamage()) .repairMaterials(customItemData.repairMaterials()) .hasSuspiciousStewEffect(false) - .customItemOptions(Object2IntMaps.emptyMap()) + .customItemOptions(Collections.emptyList()) .build(); NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 6c01ee9d2..f928361cc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -95,7 +95,10 @@ public class ItemRegistryPopulator { boolean customItemsAllowed = GeyserImpl.getInstance().getConfig().isAddNonBedrockItems(); - Multimap customItems = MultimapBuilder.hashKeys().hashSetValues().build(); + // List values here is important compared to HashSet - we need to preserve the order of what's given to us + // (as of 1.19.2 Java) to replicate some edge cases in Java predicate behavior where it checks from the bottom + // of the list first, then ascends. + Multimap customItems = MultimapBuilder.hashKeys().arrayListValues().build(); List nonVanillaCustomItems; MappingsConfigReader mappingsConfigReader = new MappingsConfigReader(); @@ -468,10 +471,10 @@ public class ItemRegistryPopulator { } // Add the custom item properties, if applicable - Object2IntMap customItemOptions; + List> customItemOptions; Collection customItemsToLoad = customItems.get(javaIdentifier); if (customItemsAllowed && !customItemsToLoad.isEmpty()) { - customItemOptions = new Object2IntOpenHashMap<>(customItemsToLoad.size()); + customItemOptions = new ObjectArrayList<>(customItemsToLoad.size()); for (CustomItemData customItem : customItemsToLoad) { int customProtocolId = nextFreeBedrockId++; @@ -491,12 +494,15 @@ public class ItemRegistryPopulator { entries.put(customMapping.stringId(), customMapping.startGamePacketItemEntry()); // ComponentItemData - used to register some custom properties componentItemData.add(customMapping.componentItemData()); - customItemOptions.put(customItem.customItemOptions(), customProtocolId); + customItemOptions.add(ObjectIntPair.of(customItem.customItemOptions(), customProtocolId)); customIdMappings.put(customMapping.integerId(), customMapping.stringId()); } + + // Important for later to find the best match and accurately replicate Java behavior + Collections.reverse(customItemOptions); } else { - customItemOptions = Object2IntMaps.emptyMap(); + customItemOptions = Collections.emptyList(); } mappingBuilder.customItemOptions(customItemOptions); @@ -550,7 +556,7 @@ public class ItemRegistryPopulator { .bedrockData(0) .bedrockBlockId(-1) .stackSize(1) - .customItemOptions(Object2IntMaps.emptyMap()) + .customItemOptions(Collections.emptyList()) .build(); if (customItemsAllowed) { @@ -567,7 +573,7 @@ public class ItemRegistryPopulator { .bedrockData(0) .bedrockBlockId(-1) .stackSize(1) - .customItemOptions(Object2IntMaps.emptyMap()) // TODO check for custom items with furnace minecart + .customItemOptions(Collections.emptyList()) // TODO check for custom items with furnace minecart .build()); creativeItems.add(ItemData.builder() diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java index 12ba7d208..e3d34b0ca 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.registry.type; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Value; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.item.custom.CustomItemOptions; -import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.registry.BlockRegistries; +import java.util.Collections; +import java.util.List; import java.util.Set; @Value @@ -41,8 +41,8 @@ import java.util.Set; @EqualsAndHashCode public class ItemMapping { public static final ItemMapping AIR = new ItemMapping("minecraft:air", "minecraft:air", 0, 0, 0, - BlockRegistries.BLOCKS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getBedrockAirId(), - 64, null, null, null, Object2IntMaps.emptyMap(), 0, null, false); + 0, // Air is never sent in full over the network for this to serialize. + 64, null, null, null, Collections.emptyList(), 0, null, false); String javaIdentifier; String bedrockIdentifier; @@ -62,7 +62,8 @@ public class ItemMapping { String translationString; - Object2IntMap customItemOptions; + @NonNull + List> customItemOptions; int maxDamage; diff --git a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java index 86e015c0f..340674119 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.text; +import it.unimi.dsi.fastutil.objects.ObjectArrays; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; @@ -173,6 +174,16 @@ public class GeyserLocale { return localeProp.isEmpty() ? null : locale; } + /** + * Get a formatted language string with the default locale for Geyser + * + * @param key Language string to translate + * @return Translated string or the original message if it was not found in the given locale + */ + public static String getLocaleStringLog(String key) { + return getLocaleStringLog(key, ObjectArrays.EMPTY_ARRAY); + } + /** * Get a formatted language string with the default locale for Geyser * @@ -184,6 +195,17 @@ public class GeyserLocale { return getPlayerLocaleString(key, getDefaultLocale(), values); } + /** + * Get a formatted language string with the given locale for Geyser + * + * @param key Language string to translate + * @param locale Locale to translate to + * @return Translated string or the original message if it was not found in the given locale + */ + public static String getPlayerLocaleString(String key, String locale) { + return getPlayerLocaleString(key, locale, ObjectArrays.EMPTY_ARRAY); + } + /** * Get a formatted language string with the given locale for Geyser * diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java new file mode 100644 index 000000000..29aa2f748 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.inventory.item; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import org.geysermc.geyser.api.item.custom.CustomItemOptions; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.registry.type.ItemMapping; + +import java.util.List; +import java.util.OptionalInt; + +/** + * This is only a separate class for testing purposes so we don't have to load in GeyserImpl in ItemTranslator. + */ +final class CustomItemTranslator { + + static int getCustomItem(CompoundTag nbt, ItemMapping mapping) { + if (nbt == null) { + return -1; + } + List> customMappings = mapping.getCustomItemOptions(); + if (customMappings.isEmpty()) { + return -1; + } + + int customModelData = nbt.get("CustomModelData") instanceof IntTag customModelDataTag ? customModelDataTag.getValue() : 0; + int damage = nbt.get("Damage") instanceof IntTag damageTag ? damageTag.getValue() : 0; + boolean unbreakable = !isDamaged(mapping, nbt, damage); + + for (ObjectIntPair mappingTypes : customMappings) { + CustomItemOptions options = mappingTypes.key(); + + // Code note: there may be two or more conditions that a custom item must follow, hence the "continues" + // here with the return at the end. + + // Implementation details: Java's predicate system works exclusively on comparing float numbers. + // A value doesn't necessarily have to match 100%; it just has to be the first to meet all predicate conditions. + // This is also why the order of iteration is important as the first to match will be the chosen display item. + // For example, if CustomModelData is set to 2f as the requirement, then the NBT can be any number greater or equal (2, 3, 4...) + // The same behavior exists for Damage (in fraction form instead of whole numbers), + // and Damaged/Unbreakable handles no damage as 0f and damaged as 1f. + + if (unbreakable && options.unbreakable() != TriState.TRUE) { + continue; + } + + OptionalInt customModelDataOption = options.customModelData(); + if (customModelDataOption.isPresent() && customModelData < customModelDataOption.getAsInt()) { + continue; + } + + OptionalInt damagePredicate = options.damagePredicate(); + if (damagePredicate.isPresent() && damage < damagePredicate.getAsInt()) { + continue; + } + + return mappingTypes.valueInt(); + } + return -1; + } + + /* These two functions are based off their Mojmap equivalents from 1.19.2 */ + + private static boolean isDamaged(ItemMapping mapping, CompoundTag nbt, int damage) { + return isDamagableItem(mapping, nbt) && damage > 0; + } + + private static boolean isDamagableItem(ItemMapping mapping, CompoundTag nbt) { + if (mapping.getMaxDamage() > 0) { + Tag unbreakableTag = nbt.get("Unbreakable"); + return unbreakableTag != null && unbreakableTag.getValue() instanceof Number number && number.byteValue() == 0; + } + return false; + } + + private CustomItemTranslator() { + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java index b36833cb1..ab3feae5f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java @@ -34,12 +34,9 @@ import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.item.custom.CustomItemOptions; -import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; @@ -173,18 +170,18 @@ public abstract class ItemTranslator { builder.blockRuntimeId(bedrockItem.getBedrockBlockId()); } - translateCustomItem(nbt, builder, bedrockItem); - if (nbt != null) { // Translate the canDestroy and canPlaceOn Java NBT ListTag canDestroy = nbt.get("CanDestroy"); - String[] canBreak = new String[0]; ListTag canPlaceOn = nbt.get("CanPlaceOn"); - String[] canPlace = new String[0]; - canBreak = getCanModify(canDestroy, canBreak); - canPlace = getCanModify(canPlaceOn, canPlace); - builder.canBreak(canBreak); - builder.canPlace(canPlace); + String[] canBreak = getCanModify(canDestroy); + String[] canPlace = getCanModify(canPlaceOn); + if (canBreak != null) { + builder.canBreak(canBreak); + } + if (canPlace != null) { + builder.canPlace(canPlace); + } } return builder.build(); @@ -246,12 +243,11 @@ public abstract class ItemTranslator { * In Java, this is treated as normal NBT, but in Bedrock, these arguments are extra parts of the item data itself. * * @param canModifyJava the list of items in Java - * @param canModifyBedrock the empty list of items in Bedrock * @return the new list of items in Bedrock */ - private static String[] getCanModify(ListTag canModifyJava, String[] canModifyBedrock) { + private static String[] getCanModify(ListTag canModifyJava) { if (canModifyJava != null && canModifyJava.size() > 0) { - canModifyBedrock = new String[canModifyJava.size()]; + String[] canModifyBedrock = new String[canModifyJava.size()]; for (int i = 0; i < canModifyBedrock.length; i++) { // Get the Java identifier of the block that can be placed String block = ((StringTag) canModifyJava.get(i)).getValue(); @@ -261,8 +257,9 @@ public abstract class ItemTranslator { // This will unfortunately be limited - for example, beds and banners will be translated weirdly canModifyBedrock[i] = BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(block, block).replace("minecraft:", ""); } + return canModifyBedrock; } - return canModifyBedrock; + return null; } /** @@ -276,7 +273,7 @@ public abstract class ItemTranslator { ItemMapping mapping = ITEM_STACK_TRANSLATORS.getOrDefault(javaId, DEFAULT_TRANSLATOR) .getItemMapping(javaId, itemStack.getNbt(), session.getItemMappings()); - int customItemId = getCustomItem(itemStack.getNbt(), mapping); + int customItemId = CustomItemTranslator.getCustomItem(itemStack.getNbt(), mapping); if (customItemId == -1) { // No custom item return mapping.getBedrockId(); @@ -329,66 +326,26 @@ public abstract class ItemTranslator { } protected NbtMap translateNbtToBedrock(CompoundTag tag) { - NbtMapBuilder builder = NbtMap.builder(); - if (tag.getValue() != null && !tag.getValue().isEmpty()) { - for (String str : tag.getValue().keySet()) { - Tag javaTag = tag.get(str); + if (!tag.getValue().isEmpty()) { + NbtMapBuilder builder = NbtMap.builder(); + for (Tag javaTag : tag.values()) { Object translatedTag = translateToBedrockNBT(javaTag); if (translatedTag == null) continue; builder.put(javaTag.getName(), translatedTag); } + return builder.build(); } - return builder.build(); + return NbtMap.EMPTY; } private Object translateToBedrockNBT(Tag tag) { - if (tag instanceof ByteArrayTag) { - return ((ByteArrayTag) tag).getValue(); - } - - if (tag instanceof ByteTag) { - return ((ByteTag) tag).getValue(); - } - - if (tag instanceof DoubleTag) { - return ((DoubleTag) tag).getValue(); - } - - if (tag instanceof FloatTag) { - return ((FloatTag) tag).getValue(); - } - - if (tag instanceof IntArrayTag) { - return ((IntArrayTag) tag).getValue(); - } - - if (tag instanceof IntTag) { - return ((IntTag) tag).getValue(); - } - - if (tag instanceof LongArrayTag) { - //Long array tag does not exist in BE - //LongArrayTag longArrayTag = (LongArrayTag) tag; - //return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); - return null; - } - - if (tag instanceof LongTag) { - return ((LongTag) tag).getValue(); - } - - if (tag instanceof ShortTag) { - return ((ShortTag) tag).getValue(); - } - - if (tag instanceof StringTag) { - return ((StringTag) tag).getValue(); + if (tag instanceof CompoundTag compoundTag) { + return translateNbtToBedrock(compoundTag); } if (tag instanceof ListTag listTag) { - List tagList = new ArrayList<>(); for (Tag value : listTag) { tagList.add(translateToBedrockNBT(value)); @@ -400,11 +357,14 @@ public abstract class ItemTranslator { return new NbtList(type, tagList); } - if (tag instanceof CompoundTag compoundTag) { - return translateNbtToBedrock(compoundTag); + if (tag instanceof LongArrayTag) { + //Long array tag does not exist in BE + //LongArrayTag longArrayTag = (LongArrayTag) tag; + //return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); + return null; } - return null; + return tag.getValue(); } private CompoundTag translateToJavaNBT(String name, NbtMap tag) { @@ -544,87 +504,10 @@ public abstract class ItemTranslator { * Translates the custom model data of an item */ private static void translateCustomItem(CompoundTag nbt, ItemData.Builder builder, ItemMapping mapping) { - int bedrockId = getCustomItem(nbt, mapping); + int bedrockId = CustomItemTranslator.getCustomItem(nbt, mapping); if (bedrockId != -1) { builder.id(bedrockId); } } - private static int getCustomItem(CompoundTag nbt, ItemMapping mapping) { - if (nbt == null) { - return -1; - } - Object2IntMap customMappings = mapping.getCustomItemOptions(); - if (customMappings.isEmpty()) { - return -1; - } - int customModelData = nbt.get("CustomModelData") instanceof IntTag customModelDataTag ? customModelDataTag.getValue() : 0; - TriState unbreakable = TriState.fromBoolean(nbt.get("Unbreakable") instanceof ByteTag unbreakableTag && unbreakableTag.getValue() == 1); - int damage = nbt.get("Damage") instanceof IntTag damageTag ? damageTag.getValue() : 0; - for (Object2IntMap.Entry mappingTypes : customMappings.object2IntEntrySet()) { - CustomItemOptions options = mappingTypes.getKey(); - - TriState unbreakableOption = options.unbreakable(); - if (unbreakableOption == unbreakable) { // Implementation note: if the option is NOT_SET then this comparison will always be false because of how the item unbreaking TriState is created - return mappingTypes.getIntValue(); - } - - OptionalInt customModelDataOption = options.customModelData(); - if (customModelDataOption.isPresent() && customModelDataOption.getAsInt() == customModelData) { - return mappingTypes.getIntValue(); - } - - OptionalInt damagePredicate = options.damagePredicate(); - if (damagePredicate.isPresent() && damagePredicate.getAsInt() == damage) { - return mappingTypes.getIntValue(); - } - } - return -1; - } - - /** - * Checks if an {@link ItemStack} is equal to another item stack - * - * @param itemStack the item stack to check - * @param equalsItemStack the item stack to check if equal to - * @param checkAmount if the amount should be taken into account - * @param trueIfAmountIsGreater if this should return true if the amount of the - * first item stack is greater than that of the second - * @param checkNbt if NBT data should be checked - * @return if an item stack is equal to another item stack - */ - public boolean equals(ItemStack itemStack, ItemStack equalsItemStack, boolean checkAmount, boolean trueIfAmountIsGreater, boolean checkNbt) { - if (itemStack.getId() != equalsItemStack.getId()) { - return false; - } - if (checkAmount) { - if (trueIfAmountIsGreater) { - if (itemStack.getAmount() < equalsItemStack.getAmount()) { - return false; - } - } else { - if (itemStack.getAmount() != equalsItemStack.getAmount()) { - return false; - } - } - } - - if (!checkNbt) { - return true; - } - if ((itemStack.getNbt() == null || itemStack.getNbt().isEmpty()) && (equalsItemStack.getNbt() != null && !equalsItemStack.getNbt().isEmpty())) { - return false; - } - - if ((itemStack.getNbt() != null && !itemStack.getNbt().isEmpty() && (equalsItemStack.getNbt() == null || !equalsItemStack.getNbt().isEmpty()))) { - return false; - } - - if (itemStack.getNbt() != null && equalsItemStack.getNbt() != null) { - return itemStack.getNbt().equals(equalsItemStack.getNbt()); - } - - return true; - } - } diff --git a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java new file mode 100644 index 000000000..900feef72 --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.inventory.item; + +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import org.geysermc.geyser.api.item.custom.CustomItemOptions; +import org.geysermc.geyser.api.util.TriState; +import org.geysermc.geyser.item.GeyserCustomItemOptions; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.OptionalInt; + +public class CustomItemsTest { + private ItemMapping testMappingWithDamage; + private Object2IntMap tagToCustomItemWithDamage; + + @Before + public void setup() { + CustomItemOptions a = new GeyserCustomItemOptions(TriState.TRUE, OptionalInt.of(2), OptionalInt.empty()); + CustomItemOptions b = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.of(5), OptionalInt.empty()); + CustomItemOptions c = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.empty(), OptionalInt.of(3)); + CustomItemOptions d = new GeyserCustomItemOptions(TriState.TRUE, OptionalInt.empty(), OptionalInt.of(8)); + CustomItemOptions e = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.empty(), OptionalInt.of(12)); + CustomItemOptions f = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.of(8), OptionalInt.of(6)); + + Object2IntMap optionsToId = new Object2IntArrayMap<>(); + // Order here is important, hence why we're using an array map + optionsToId.put(f, 6); + optionsToId.put(e, 5); + optionsToId.put(d, 4); + optionsToId.put(c, 3); + optionsToId.put(b, 2); + optionsToId.put(a, 1); + + tagToCustomItemWithDamage = new Object2IntOpenHashMap<>(); + + CompoundTag tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 6)); + // Test item with no damage should be treated as unbreakable + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); + + tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 3)); + tag.put(new ByteTag("Unbreakable", (byte) 1)); + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); + + tag = new CompoundTag(""); + tag.put(new IntTag("Damage", 16)); + tag.put(new ByteTag("Unbreakable", (byte) 0)); + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(e)); + + tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 7)); + tag.put(new IntTag("Damage", 6)); + tag.put(new ByteTag("Unbreakable", (byte) 0)); + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(c)); + + tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 8)); + tag.put(new IntTag("Damage", 6)); + tag.put(new ByteTag("Unbreakable", (byte) 1)); + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); + + tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 9)); + tag.put(new IntTag("Damage", 6)); + tag.put(new ByteTag("Unbreakable", (byte) 0)); + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(f)); + + testMappingWithDamage = ItemMapping.builder() + .customItemOptions(optionsToId.object2IntEntrySet().stream().map(entry -> ObjectIntPair.of(entry.getKey(), entry.getIntValue())).toList()) + .maxDamage(100) + .build(); + // Later, possibly add a condition with a mapping with no damage + } + + @Test + public void testCustomItems() { + for (Object2IntMap.Entry entry : this.tagToCustomItemWithDamage.object2IntEntrySet()) { + int id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithDamage); + Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getIntValue(), id); + } + } +} From 8bf8b22d6bf5beba316cbceb333a1d4b199e9585 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:21:58 -0400 Subject: [PATCH 218/290] Fix some regressions in custom item handling --- .../inventory/item/CustomItemTranslator.java | 42 ++++++----- .../inventory/item/CustomItemsTest.java | 72 +++++++++++++++---- 2 files changed, 82 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java index 29aa2f748..82a8c9de1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java @@ -51,8 +51,9 @@ final class CustomItemTranslator { } int customModelData = nbt.get("CustomModelData") instanceof IntTag customModelDataTag ? customModelDataTag.getValue() : 0; - int damage = nbt.get("Damage") instanceof IntTag damageTag ? damageTag.getValue() : 0; - boolean unbreakable = !isDamaged(mapping, nbt, damage); + boolean checkDamage = mapping.getMaxDamage() > 0; + int damage = !checkDamage ? 0 : nbt.get("Damage") instanceof IntTag damageTag ? damageTag.getValue() : 0; + boolean unbreakable = checkDamage && !isDamaged(nbt, damage); for (ObjectIntPair mappingTypes : customMappings) { CustomItemOptions options = mappingTypes.key(); @@ -67,8 +68,21 @@ final class CustomItemTranslator { // The same behavior exists for Damage (in fraction form instead of whole numbers), // and Damaged/Unbreakable handles no damage as 0f and damaged as 1f. - if (unbreakable && options.unbreakable() != TriState.TRUE) { - continue; + if (checkDamage) { + if (unbreakable && options.unbreakable() == TriState.FALSE) { + continue; + } + + OptionalInt damagePredicate = options.damagePredicate(); + if (damagePredicate.isPresent() && damage < damagePredicate.getAsInt()) { + continue; + } + } else { + if (options.unbreakable() != TriState.NOT_SET || options.damagePredicate().isPresent()) { + // These will never match on this item. 1.19.2 behavior + // Maybe move this to CustomItemRegistryPopulator since it'll be the same for every item? If so, add a test. + continue; + } } OptionalInt customModelDataOption = options.customModelData(); @@ -76,11 +90,6 @@ final class CustomItemTranslator { continue; } - OptionalInt damagePredicate = options.damagePredicate(); - if (damagePredicate.isPresent() && damage < damagePredicate.getAsInt()) { - continue; - } - return mappingTypes.valueInt(); } return -1; @@ -88,16 +97,15 @@ final class CustomItemTranslator { /* These two functions are based off their Mojmap equivalents from 1.19.2 */ - private static boolean isDamaged(ItemMapping mapping, CompoundTag nbt, int damage) { - return isDamagableItem(mapping, nbt) && damage > 0; + private static boolean isDamaged(CompoundTag nbt, int damage) { + return isDamagableItem(nbt) && damage > 0; } - private static boolean isDamagableItem(ItemMapping mapping, CompoundTag nbt) { - if (mapping.getMaxDamage() > 0) { - Tag unbreakableTag = nbt.get("Unbreakable"); - return unbreakableTag != null && unbreakableTag.getValue() instanceof Number number && number.byteValue() == 0; - } - return false; + private static boolean isDamagableItem(CompoundTag nbt) { + // mapping.getMaxDamage > 0 should also be checked (return false if not true) but we already check prior to this function + Tag unbreakableTag = nbt.get("Unbreakable"); + // Tag must either not be present or be set to false + return unbreakableTag == null || !(unbreakableTag.getValue() instanceof Number number) || number.byteValue() == 0; } private CustomItemTranslator() { diff --git a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java index 900feef72..6870558d0 100644 --- a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java +++ b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java @@ -40,11 +40,14 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.util.List; import java.util.OptionalInt; public class CustomItemsTest { private ItemMapping testMappingWithDamage; private Object2IntMap tagToCustomItemWithDamage; + private ItemMapping testMappingWithNoDamage; + private Object2IntMap tagToCustomItemWithNoDamage; @Before public void setup() { @@ -54,9 +57,11 @@ public class CustomItemsTest { CustomItemOptions d = new GeyserCustomItemOptions(TriState.TRUE, OptionalInt.empty(), OptionalInt.of(8)); CustomItemOptions e = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.empty(), OptionalInt.of(12)); CustomItemOptions f = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.of(8), OptionalInt.of(6)); + CustomItemOptions g = new GeyserCustomItemOptions(TriState.NOT_SET, OptionalInt.of(20), OptionalInt.empty()); Object2IntMap optionsToId = new Object2IntArrayMap<>(); // Order here is important, hence why we're using an array map + optionsToId.put(g, 7); optionsToId.put(f, 6); optionsToId.put(e, 5); optionsToId.put(d, 4); @@ -72,38 +77,70 @@ public class CustomItemsTest { tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 3)); - tag.put(new ByteTag("Unbreakable", (byte) 1)); + addCustomModelData(20, tag); + // Test that an unbreakable item isn't tested for Damaged if there is no damaged predicate + tagToCustomItemWithDamage.put(tag, optionsToId.getInt(g)); + + tag = new CompoundTag(""); + addCustomModelData(3, tag); + setUnbreakable(true, tag); tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); tag = new CompoundTag(""); - tag.put(new IntTag("Damage", 16)); - tag.put(new ByteTag("Unbreakable", (byte) 0)); + addDamage(16, tag); + setUnbreakable(false, tag); tagToCustomItemWithDamage.put(tag, optionsToId.getInt(e)); tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 7)); - tag.put(new IntTag("Damage", 6)); - tag.put(new ByteTag("Unbreakable", (byte) 0)); + addCustomModelData(7, tag); + addDamage(6, tag); + setUnbreakable(false, tag); tagToCustomItemWithDamage.put(tag, optionsToId.getInt(c)); tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 8)); - tag.put(new IntTag("Damage", 6)); - tag.put(new ByteTag("Unbreakable", (byte) 1)); + addCustomModelData(9, tag); + addDamage(6, tag); + setUnbreakable(true, tag); tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 9)); - tag.put(new IntTag("Damage", 6)); - tag.put(new ByteTag("Unbreakable", (byte) 0)); + addCustomModelData(9, tag); + addDamage(6, tag); + setUnbreakable(false, tag); tagToCustomItemWithDamage.put(tag, optionsToId.getInt(f)); + List> customItemOptions = optionsToId.object2IntEntrySet().stream().map(entry -> ObjectIntPair.of(entry.getKey(), entry.getIntValue())).toList(); + testMappingWithDamage = ItemMapping.builder() - .customItemOptions(optionsToId.object2IntEntrySet().stream().map(entry -> ObjectIntPair.of(entry.getKey(), entry.getIntValue())).toList()) + .customItemOptions(customItemOptions) .maxDamage(100) .build(); - // Later, possibly add a condition with a mapping with no damage + + // Test differences with items with no max damage + + tagToCustomItemWithNoDamage = new Object2IntOpenHashMap<>(); + + tag = new CompoundTag(""); + tag.put(new IntTag("CustomModelData", 2)); + // Damage predicates existing mean an item will never match if the item mapping has no max damage + tagToCustomItemWithNoDamage.put(tag, -1); + + testMappingWithNoDamage = ItemMapping.builder() + .customItemOptions(customItemOptions) + .maxDamage(0) + .build(); + } + + private void addCustomModelData(int value, CompoundTag tag) { + tag.put(new IntTag("CustomModelData", value)); + } + + private void addDamage(int value, CompoundTag tag) { + tag.put(new IntTag("Damage", value)); + } + + private void setUnbreakable(boolean value, CompoundTag tag) { + tag.put(new ByteTag("Unbreakable", (byte) (value ? 1 : 0))); } @Test @@ -112,5 +149,10 @@ public class CustomItemsTest { int id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithDamage); Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getIntValue(), id); } + + for (Object2IntMap.Entry entry : this.tagToCustomItemWithNoDamage.object2IntEntrySet()) { + int id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithNoDamage); + Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getIntValue(), id); + } } } From bd613987cea936a5f7e4a00b5b79a4115630acb8 Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Sun, 16 Oct 2022 02:26:02 +0200 Subject: [PATCH 219/290] Fix empty chunk encoding --- .../protocol/java/JavaLoginTranslator.java | 5 +-- .../protocol/java/JavaRespawnTranslator.java | 4 -- .../JavaLevelChunkWithLightTranslator.java | 10 ++--- .../org/geysermc/geyser/util/ChunkUtils.java | 42 ++++++++++--------- .../geysermc/geyser/util/DimensionUtils.java | 2 + 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 6aa613b24..978d4b6fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -99,6 +99,8 @@ public class JavaLoginTranslator extends PacketTranslator> 4; + // Estimate chunk size int size = 0; for (int i = 0; i < sectionCount; i++) { @@ -294,9 +296,8 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4; int dimensionOffset = bedrockDimension.minY() >> 4; for (int i = 0; i < biomeCount; i++) { int biomeYOffset = dimensionOffset + i; @@ -331,7 +330,6 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4; + + byte[] payload; + + // Allocate output buffer + ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(ChunkUtils.EMPTY_BIOME_DATA.length * bedrockSubChunkCount + 1); // Consists only of biome data and border blocks + try { + byteBuf.writeBytes(EMPTY_BIOME_DATA); + for (int i = 1; i < bedrockSubChunkCount; i++) { + byteBuf.writeByte((127 << 1) | 1); + } + + byteBuf.writeByte(0); // Border blocks - Edu edition only + + payload = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(payload); + } finally { + byteBuf.release(); + } + LevelChunkPacket data = new LevelChunkPacket(); data.setChunkX(chunkX); data.setChunkZ(chunkZ); data.setSubChunksLength(0); - data.setData(EMPTY_CHUNK_DATA); + data.setData(payload); data.setCachingEnabled(false); session.sendUpstreamPacket(data); diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 7e5d65a97..59f5ed55d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -94,6 +94,8 @@ public class DimensionUtils { changeDimensionPacket.setPosition(pos); session.sendUpstreamPacket(changeDimensionPacket); session.setDimension(javaDimension); + session.setDimensionType(session.getDimensions().get(javaDimension)); + ChunkUtils.loadDimension(session); player.setPosition(pos); session.setSpawned(false); session.setLastChunkPosition(null); From 7bf9b92cbb60ca37262f8efd2d089a686a531273 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 16 Oct 2022 20:21:29 -0400 Subject: [PATCH 220/290] Cleanup buildscript, add github actions --- .github/workflows/pullrequest.yml | 7 +++++++ bootstrap/fabric/build.gradle.kts | 20 ------------------- .../fabric/src/main/resources/fabric.mod.json | 8 ++++---- .../kotlin/geyser.base-conventions.gradle.kts | 3 ++- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index cb55c2675..39e9fe188 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -19,6 +19,13 @@ jobs: uses: snickerbockers/submodules-init@v4 - name: Build with Gradle run: ./gradlew build + + - name: Archive artifacts (Geyser Fabric) + uses: actions/upload-artifact@v2 + if: success() + with: + name: Geyser Fabric + path: bootstrap/fabric/build/libs/Geyser-Fabric.jar - name: Archive artifacts (Geyser Standalone) uses: actions/upload-artifact@v2 if: success() diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 5c2409be8..7e767afe0 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -51,21 +51,6 @@ repositories { } tasks { - processResources { -// inputs.property "version", project.version -// -// filesMatching("fabric.mod.json") { -// expand "version": project.version -// } - } - - // 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 - compileJava { - 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. @@ -79,11 +64,6 @@ tasks { 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") - archiveClassifier.set("unshaded") // We don't want it included in the archived artifacts - } - - jar { - from("LICENSE") } remapJar { diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 9d66ca08c..4460e277b 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -1,14 +1,14 @@ { "schemaVersion": 1, - "id": "geyser-fabric", + "id": "${id}-fabric", "version": "${version}", - "name": "Geyser-Fabric", + "name": "${name}-Fabric", "description": "A bridge/proxy allowing you to connect to Minecraft: Java Edition servers with Minecraft: Bedrock Edition. ", "authors": [ - "GeyserMC" + "${author}" ], "contact": { - "website": "https://geysermc.org", + "website": "${url}", "repo": "https://github.com/GeyserMC/Geyser-Fabric" }, "license": "MIT", diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index bd50c6ea0..44a74db3d 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -9,7 +9,8 @@ dependencies { tasks { processResources { - filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json")) { + // Spigot, BungeeCord, Velocity, Sponge, Fabric + filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json", "fabric.mod.json")) { expand( "id" to "geyser", "name" to "Geyser", From 675e70be6673050dc52e0b470960f965566e1f92 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 16 Oct 2022 22:47:26 -0400 Subject: [PATCH 221/290] Fix shaded jar --- Jenkinsfile | 2 +- bootstrap/fabric/build.gradle.kts | 10 +++++ .../platform/fabric/GeyserFabricMain.java | 45 +++++++++++++++++++ build.gradle.kts | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java diff --git a/Jenkinsfile b/Jenkinsfile index 0123a2771..065ca48c4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,7 +20,7 @@ pipeline { } post { success { - archiveArtifacts artifacts: 'bootstrap/**/build/libs/*.jar', excludes: 'bootstrap/**/build/libs/*-sources.jar,bootstrap/**/build/libs/*-unshaded.jar', fingerprint: true + archiveArtifacts artifacts: 'bootstrap/**/build/libs/Geyser-*.jar', fingerprint: true } } } diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 7e767afe0..8729e671c 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -50,6 +50,10 @@ repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") } +application { + mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain") +} + tasks { // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task // if it is present. @@ -60,6 +64,12 @@ tasks { } shadowJar { + // Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be + configurations = listOf(project.configurations.shadow.get()) + // The remapped shadowJar is the final desired Geyser-Fabric.jar + archiveVersion.set(project.version.toString()) + archiveClassifier.set("shaded") + 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") diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java new file mode 100644 index 000000000..354dbbf77 --- /dev/null +++ b/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2022 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.geyser.GeyserMain; + +public class GeyserFabricMain extends GeyserMain { + + public static void main(String[] args) { + new GeyserFabricMain().displayMessage(); + } + + @Override + public String getPluginType() { + return "Fabric"; + } + + @Override + public String getPluginFolder() { + return "mods"; + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 7371978d3..06c2e987b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,7 @@ allprojects { } val platforms = setOf( + projects.fabric, projects.bungeecord, projects.spigot, projects.sponge, From 379453191009f381744ff0d2b2e6a5bd6925f10e Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 17 Oct 2022 00:25:54 -0400 Subject: [PATCH 222/290] Fix application main --- bootstrap/fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 8729e671c..36d1163bd 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -51,7 +51,7 @@ repositories { } application { - mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain") + mainClass.set("org.geysermc.platform.fabric.GeyserFabricMain") } tasks { From 237a69d3c28d1d77a6dd85e8513444e288b3e1cc Mon Sep 17 00:00:00 2001 From: SupremeMortal <6178101+SupremeMortal@users.noreply.github.com> Date: Mon, 17 Oct 2022 22:08:52 +0100 Subject: [PATCH 223/290] Refactor package and cleanup dependencies for Fabric --- bootstrap/fabric/build.gradle.kts | 19 +++++-------------- .../fabric/GeyserFabricConfiguration.java | 4 ++-- .../platform/fabric/GeyserFabricDumpInfo.java | 4 ++-- .../platform/fabric/GeyserFabricLogger.java | 4 ++-- .../platform/fabric/GeyserFabricMain.java | 2 +- .../platform/fabric/GeyserFabricMod.java | 10 +++++----- .../fabric/GeyserFabricPermissions.java | 4 ++-- .../fabric/GeyserServerPortGetter.java | 4 ++-- .../{ => geyser}/platform/fabric/ModInfo.java | 4 ++-- .../fabric/command/FabricCommandSender.java | 6 +++--- .../command/GeyserFabricCommandExecutor.java | 8 ++++---- .../command/GeyserFabricCommandManager.java | 4 ++-- .../mixin/client/IntegratedServerMixin.java | 8 ++++---- .../server/MinecraftDedicatedServerMixin.java | 6 +++--- .../world/GeyserFabricWorldManager.java | 8 ++++---- .../fabric/src/main/resources/fabric.mod.json | 2 +- .../main/resources/geyser-fabric.mixins.json | 2 +- gradle.properties | 14 +------------- gradle/libs.versions.toml | 6 ++++++ 19 files changed, 52 insertions(+), 67 deletions(-) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricConfiguration.java (95%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricDumpInfo.java (96%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricLogger.java (95%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricMain.java (97%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricMod.java (97%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserFabricPermissions.java (94%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/GeyserServerPortGetter.java (95%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/ModInfo.java (95%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/command/FabricCommandSender.java (94%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/command/GeyserFabricCommandExecutor.java (94%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/command/GeyserFabricCommandManager.java (93%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/mixin/client/IntegratedServerMixin.java (92%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java (92%) rename bootstrap/fabric/src/main/java/org/geysermc/{ => geyser}/platform/fabric/world/GeyserFabricWorldManager.java (96%) diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 36d1163bd..2a6d1422c 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -10,23 +10,14 @@ java { sourceCompatibility = JavaVersion.VERSION_17 } -//archivesBaseName = project.archives_base_name -//version = project.mod_version -//group = project.maven_group - -val minecraftVersion = project.property("minecraft_version") as String -val yarnVersion = project.property("yarn_mappings") as String -val loaderVersion = project.property("loader_version") as String -val fabricVersion = project.property("fabric_version") as String - dependencies { //to change the versions see the gradle.properties file - minecraft("com.mojang:minecraft:$minecraftVersion") - mappings("net.fabricmc:yarn:$yarnVersion:v2") - modImplementation("net.fabricmc:fabric-loader:$loaderVersion") + minecraft(libs.fabric.minecraft) + mappings(libs.fabric.yarn) { artifact { classifier = "v2" } } + modImplementation(libs.fabric.loader) // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + modImplementation(libs.fabric.api) // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. @@ -51,7 +42,7 @@ repositories { } application { - mainClass.set("org.geysermc.platform.fabric.GeyserFabricMain") + mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain") } tasks { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java similarity index 95% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java index b49707871..f557d16c0 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricConfiguration.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import com.fasterxml.jackson.annotation.JsonIgnore; import net.fabricmc.loader.api.FabricLoader; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java similarity index 96% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java index e3997da51..e09129fc1 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java similarity index 95% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java index 9c85a21f2..a6ee77f41 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricLogger.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java similarity index 97% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java index 354dbbf77..f3f63324a 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMain.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import org.geysermc.geyser.GeyserMain; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java similarity index 97% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index cdd7d358a..f565daea3 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.api.EnvType; @@ -49,9 +49,9 @@ 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; +import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; +import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandManager; +import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; import org.jetbrains.annotations.Nullable; import java.io.File; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java similarity index 94% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java index fc08b052a..a625f6d1f 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserFabricPermissions.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java similarity index 95% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java index 5af7775a8..7e856c5ce 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/GeyserServerPortGetter.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import net.minecraft.server.MinecraftServer; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java similarity index 95% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java index da753c44f..b9137c438 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/ModInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric; +package org.geysermc.geyser.platform.fabric; import net.fabricmc.loader.api.ModContainer; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java similarity index 94% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java index 20dee1b21..1a5e700f8 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,15 +23,15 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.command; +package org.geysermc.geyser.platform.fabric.command; 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.GeyserCommandSource; +import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.text.ChatColor; -import org.geysermc.platform.fabric.GeyserFabricMod; public class FabricCommandSender implements GeyserCommandSource { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java similarity index 94% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java index 07b8bd519..7ef77e856 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.command; +package org.geysermc.geyser.platform.fabric.command; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; @@ -31,11 +31,11 @@ import net.minecraft.server.command.ServerCommandSource; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandExecutor; +import org.geysermc.geyser.platform.fabric.GeyserFabricMod; +import org.geysermc.geyser.platform.fabric.GeyserFabricPermissions; 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; import java.util.Collections; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java similarity index 93% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java index feaf40130..d21dae319 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/command/GeyserFabricCommandManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.command; +package org.geysermc.geyser.platform.fabric.command; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandManager; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java similarity index 92% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java index 6a6d3e0e6..d329c1894 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.mixin.client; +package org.geysermc.geyser.platform.fabric.mixin.client; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -32,9 +32,9 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.text.Text; import net.minecraft.world.GameMode; +import org.geysermc.geyser.platform.fabric.GeyserFabricMod; +import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter; import org.geysermc.geyser.text.GeyserLocale; -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; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java similarity index 92% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java index a41a08342..799d94917 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.mixin.server; +package org.geysermc.geyser.platform.fabric.mixin.server; import com.mojang.datafixers.DataFixer; import net.minecraft.resource.ResourcePackManager; @@ -33,7 +33,7 @@ import net.minecraft.server.WorldGenerationProgressListenerFactory; import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.util.ApiServices; import net.minecraft.world.level.storage.LevelStorage; -import org.geysermc.platform.fabric.GeyserServerPortGetter; +import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter; import org.spongepowered.asm.mixin.Mixin; import java.net.Proxy; diff --git a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java similarity index 96% rename from bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java index 40c7fd302..be68cefb9 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.fabric.world; +package org.geysermc.geyser.platform.fabric.world; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; @@ -39,11 +39,11 @@ import net.minecraft.nbt.NbtList; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import org.geysermc.geyser.level.GeyserWorldManager; +import org.geysermc.geyser.platform.fabric.GeyserFabricMod; +import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; 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; import java.util.ArrayList; import java.util.List; diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 4460e277b..ee23dd06d 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "environment": "*", "entrypoints": { "main": [ - "org.geysermc.platform.fabric.GeyserFabricMod" + "org.geysermc.geyser.platform.fabric.GeyserFabricMod" ] }, "mixins": [ diff --git a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json index 6081bee93..c688ace36 100644 --- a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json +++ b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json @@ -1,6 +1,6 @@ { "required": true, - "package": "org.geysermc.platform.fabric.mixin", + "package": "org.geysermc.geyser.platform.fabric.mixin", "compatibilityLevel": "JAVA_16", "client": [ "client.IntegratedServerMixin" diff --git a/gradle.properties b/gradle.properties index 35cb21537..4fb72e2fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,16 +9,4 @@ version=2.1.0-SNAPSHOT org.gradle.caching=true org.gradle.parallel=true -org.gradle.vfs.watch=false - -# Fabric Properties -# check these on https://modmuss50.me/fabric.html -minecraft_version=1.19.1 -yarn_mappings=1.19.1+build.1 -loader_version=0.14.8 -# Mod Properties -maven_group=org.geysermc.platform -archives_base_name=Geyser-Fabric -# Dependencies -# check this on https://modmuss50.me/fabric.html -fabric_version=0.58.5+1.19.1 \ No newline at end of file +org.gradle.vfs.watch=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bf4688d7f..b4d7430f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,6 +62,12 @@ jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jlin paper-api = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "paper" } +# check these on https://modmuss50.me/fabric.html +fabric-minecraft = { group = "com.mojang", name = "minecraft", version = "1.19.1" } +fabric-yarn = { group = "net.fabricmc", name = "yarn", version = "1.19.1+build.1" } +fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version = "0.14.8" } +fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version = "0.58.5+1.19.1" } + adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" } bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" } checker-qual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerframework" } From 657968f87242cff668d7c289397af8c3a7798a76 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 17 Oct 2022 23:35:16 -0400 Subject: [PATCH 224/290] Indicate 1.19.31 Bedrock support --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 997bbff58..d91672eb4 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.30 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.30/1.19.31 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 4c5c099f0..844fd0f51 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -47,7 +47,9 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v554.V554_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v554.V554_CODEC.toBuilder() + .minecraftVersion("1.19.31") + .build(); /** * A list of all supported Bedrock versions that can join Geyser */ @@ -70,7 +72,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.30/1.19.31") + .build()); } /** From 0e07991edf4762975859d5541d56a3f997c95a3d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 17 Oct 2022 23:36:46 -0400 Subject: [PATCH 225/290] Changes as I was randomly staring at the code --- .../entity/type/DefaultBlockMinecartEntity.java | 2 +- .../geyser/level/chunk/bitarray/BitArrayVersion.java | 2 +- .../level/chunk/bitarray/SingletonBitArray.java | 7 +++---- .../geyser/registry/AbstractMappedRegistry.java | 11 +++++------ .../populator/CustomItemRegistryPopulator.java | 4 +++- .../org/geysermc/geyser/session/SessionManager.java | 4 ++-- .../inventory/item/nbt/CrossbowTranslator.java | 4 ++-- .../inventory/item/nbt/LeatherArmorTranslator.java | 6 ++---- .../block/entity/CampfireBlockEntityTranslator.java | 3 ++- .../translator/inventory/item/CustomItemsTest.java | 4 ++-- 10 files changed, 23 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java index ab43bf7b3..c562df476 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java @@ -57,7 +57,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity { @Override public void setCustomBlock(IntEntityMetadata entityMetadata) { - customBlock = ((IntEntityMetadata) entityMetadata).getPrimitiveValue(); + customBlock = entityMetadata.getPrimitiveValue(); if (showCustomBlock) { dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(customBlock)); diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java index d2f3e7c9e..d95767b97 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java @@ -96,7 +96,7 @@ public enum BitArrayVersion { // Padded palettes aren't able to use bitwise operations due to their padding. return new PaddedBitArray(this, size, words); } else if (this == V0) { - return new SingletonBitArray(); + return SingletonBitArray.INSTANCE; } else { return new Pow2BitArray(this, size, words); } diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java index 6e37749df..ce25ead95 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java @@ -26,13 +26,12 @@ package org.geysermc.geyser.level.chunk.bitarray; import io.netty.buffer.ByteBuf; +import it.unimi.dsi.fastutil.ints.IntArrays; public class SingletonBitArray implements BitArray { public static final SingletonBitArray INSTANCE = new SingletonBitArray(); - private static final int[] EMPTY_ARRAY = new int[0]; - - public SingletonBitArray() { + private SingletonBitArray() { } @Override @@ -56,7 +55,7 @@ public class SingletonBitArray implements BitArray { @Override public int[] getWords() { - return EMPTY_ARRAY; + return IntArrays.EMPTY_ARRAY; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java index fc4e3d022..70a3da88e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java @@ -29,8 +29,8 @@ import org.geysermc.geyser.registry.loader.RegistryLoader; import javax.annotation.Nullable; import java.util.Map; -import java.util.Optional; -import java.util.function.Function; +import java.util.OptionalInt; +import java.util.function.ToIntFunction; /** * An abstract registry holding a map of various registrations as defined by {@link M}. @@ -62,15 +62,14 @@ public abstract class AbstractMappedRegistry> extends * * @param key the key * @param mapper the mapper - * @param the type * @return the mapped value from the given key if present */ - public Optional map(K key, Function mapper) { + public OptionalInt map(K key, ToIntFunction mapper) { V value = this.get(key); if (value == null) { - return Optional.empty(); + return OptionalInt.empty(); } else { - return Optional.ofNullable(mapper.apply(value)); + return OptionalInt.of(mapper.applyAsInt(value)); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 017ede61e..1daa6d28d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; +import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.components.ToolBreakSpeedsUtils; import org.geysermc.geyser.item.components.WearableSlot; @@ -171,7 +172,8 @@ public class CustomItemRegistryPopulator { itemProperties.putBoolean("allow_off_hand", customItemData.allowOffhand()); itemProperties.putBoolean("hand_equipped", isTool); itemProperties.putInt("max_stack_size", stackSize); - if (maxDamage > 0) { + // Ignore durability if the item's predicate requires that it be unbreakable + if (maxDamage > 0 && customItemData.customItemOptions().unbreakable() != TriState.TRUE) { componentBuilder.putCompound("minecraft:durability", NbtMap.builder() .putCompound("damage_chance", NbtMap.builder() .putInt("max", 1) diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 02940e00c..7e5982ab5 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -28,9 +28,9 @@ package org.geysermc.geyser.session; import com.google.common.collect.ImmutableList; import lombok.AccessLevel; import lombok.Getter; -import lombok.NonNull; import org.geysermc.geyser.text.GeyserLocale; +import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -69,7 +69,7 @@ public final class SessionManager { } } - public GeyserSession sessionByXuid(@NonNull String xuid) { + public GeyserSession sessionByXuid(@Nonnull String xuid) { Objects.requireNonNull(xuid); for (GeyserSession session : sessions.values()) { if (session.xuid().equals(xuid)) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java index 0a4ca0686..642a43123 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java @@ -39,8 +39,8 @@ public class CrossbowTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { - if (itemTag.get("ChargedProjectiles") != null) { - ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); + ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); + if (chargedProjectiles != null) { if (!chargedProjectiles.getValue().isEmpty()) { CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java index 2fb5ec6cb..5e5920b4a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java @@ -32,13 +32,12 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.item.ItemRemapper; import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator; -import java.util.Arrays; import java.util.List; @ItemRemapper public class LeatherArmorTranslator extends NbtItemStackTranslator { - private static final List ITEMS = Arrays.asList("minecraft:leather_helmet", "minecraft:leather_chestplate", + private static final List ITEMS = List.of("minecraft:leather_helmet", "minecraft:leather_chestplate", "minecraft:leather_leggings", "minecraft:leather_boots", "minecraft:leather_horse_armor"); @Override @@ -47,10 +46,9 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator { if (displayTag == null) { return; } - IntTag color = displayTag.get("color"); + IntTag color = displayTag.remove("color"); if (color != null) { itemTag.put(new IntTag("customColor", color.getValue())); - displayTag.remove("color"); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index 6ec0effca..e36ad2d22 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.geyser.network.GameProtocol; @@ -40,7 +41,7 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { ListTag items = tag.get("Items"); int i = 1; - for (com.github.steveice10.opennbt.tag.builtin.Tag itemTag : items.getValue()) { + for (Tag itemTag : items.getValue()) { builder.put("Item" + i, getItem((CompoundTag) itemTag)); i++; } diff --git a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java index 6870558d0..145f46369 100644 --- a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java +++ b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java @@ -72,7 +72,7 @@ public class CustomItemsTest { tagToCustomItemWithDamage = new Object2IntOpenHashMap<>(); CompoundTag tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 6)); + addCustomModelData(6, tag); // Test item with no damage should be treated as unbreakable tagToCustomItemWithDamage.put(tag, optionsToId.getInt(a)); @@ -121,7 +121,7 @@ public class CustomItemsTest { tagToCustomItemWithNoDamage = new Object2IntOpenHashMap<>(); tag = new CompoundTag(""); - tag.put(new IntTag("CustomModelData", 2)); + addCustomModelData(2, tag); // Damage predicates existing mean an item will never match if the item mapping has no max damage tagToCustomItemWithNoDamage.put(tag, -1); From 144d7b000a938c179f6649e3b693dd61c0ab756a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 18 Oct 2022 12:06:18 -0400 Subject: [PATCH 226/290] Use Mojang mappings for Geyser-Fabric --- Jenkinsfile | 1 - bootstrap/fabric/build.gradle.kts | 2 +- .../platform/fabric/GeyserFabricDumpInfo.java | 6 ++-- .../platform/fabric/GeyserFabricMod.java | 23 ++++++------- .../fabric/GeyserServerPortGetter.java | 2 +- .../fabric/command/FabricCommandSender.java | 22 +++++++------ .../command/GeyserFabricCommandExecutor.java | 10 +++--- .../mixin/client/IntegratedServerMixin.java | 24 +++++++------- .../server/MinecraftDedicatedServerMixin.java | 20 ++++++------ .../world/GeyserFabricWorldManager.java | 32 +++++++++---------- gradle/libs.versions.toml | 1 - 11 files changed, 72 insertions(+), 71 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 065ca48c4..072f99154 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -101,7 +101,6 @@ pipeline { success { script { if (env.BRANCH_NAME == 'master') { - build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] build propagate: false, wait: false, job: 'GeyserMC/GeyserConnect/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)] } } diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 2a6d1422c..dac791173 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -13,7 +13,7 @@ java { dependencies { //to change the versions see the gradle.properties file minecraft(libs.fabric.minecraft) - mappings(libs.fabric.yarn) { artifact { classifier = "v2" } } + mappings(loom.officialMojangMappings()) modImplementation(libs.fabric.loader) // Fabric API. This is technically optional, but you probably want it anyway. diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java index e09129fc1..2db6a3729 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java @@ -54,12 +54,12 @@ public class GeyserFabricDumpInfo extends BootstrapDumpInfo { } } 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(); + if (AsteriskSerializer.showSensitive || (server.getLocalIp() == null || server.getLocalIp().equals("") || server.getLocalIp().equals("0.0.0.0"))) { + this.serverIP = server.getLocalIp(); } else { this.serverIP = "***"; } - this.serverPort = server.getServerPort(); + this.serverPort = server.getPort(); this.mods = new ArrayList<>(); for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index f565daea3..333a3d810 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -31,27 +31,28 @@ 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.commands.CommandSourceStack; +import net.minecraft.commands.Commands; 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.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; 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.text.GeyserLocale; -import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandManager; import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.FileUtils; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -145,7 +146,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { this.geyserConfig.setAutoconfiguredRemote(true); - String ip = server.getServerIp(); + String ip = server.getLocalIp(); int port = ((GeyserServerPortGetter) server).geyser$getServerPort(); if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) { this.geyserConfig.getRemote().setAddress(ip); @@ -185,16 +186,16 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(connector, (GeyserCommand) connector.commandManager().getCommands().get("help"), !playerCommands.contains("help")); commandExecutors.add(helpExecutor); - LiteralArgumentBuilder builder = net.minecraft.server.command.CommandManager.literal("geyser").executes(helpExecutor); + LiteralArgumentBuilder builder = Commands.literal("geyser").executes(helpExecutor); // Register all subcommands as valid 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)); + builder.then(Commands.literal(command.getKey()).executes(executor)); } - server.getCommandManager().getDispatcher().register(builder); + server.getCommands().getDispatcher().register(builder); } @Override @@ -245,7 +246,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @Override public String getMinecraftServerVersion() { - return this.server.getVersion(); + return this.server.getServerVersion(); } @Nullable diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java index 7e856c5ce..4f1c8b638 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java @@ -39,7 +39,7 @@ public interface GeyserServerPortGetter { *
  • 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, + * The reason is that {@link MinecraftServer#getPort()} 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. diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java index 1a5e700f8..0bb171e6b 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java @@ -25,31 +25,33 @@ package org.geysermc.geyser.platform.fabric.command; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.text.ChatColor; +import javax.annotation.Nonnull; + public class FabricCommandSender implements GeyserCommandSource { - private final ServerCommandSource source; + private final CommandSourceStack source; - public FabricCommandSender(ServerCommandSource source) { + public FabricCommandSender(CommandSourceStack source) { this.source = source; } @Override public String name() { - return source.getName(); + return source.getTextName(); } @Override - public void sendMessage(String message) { - if (source.getEntity() instanceof ServerPlayerEntity) { - ((ServerPlayerEntity) source.getEntity()).sendMessage(Text.literal(message), false); + public void sendMessage(@Nonnull String message) { + if (source.getEntity() instanceof ServerPlayer) { + ((ServerPlayer) source.getEntity()).displayClientMessage(Component.literal(message), false); } else { GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET)); } @@ -57,7 +59,7 @@ public class FabricCommandSender implements GeyserCommandSource { @Override public boolean isConsole() { - return !(source.getEntity() instanceof ServerPlayerEntity); + return !(source.getEntity() instanceof ServerPlayer); } @Override diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java index 7ef77e856..f691cd49e 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.platform.fabric.command; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; -import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.commands.CommandSourceStack; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandExecutor; @@ -39,7 +39,7 @@ import org.geysermc.geyser.text.GeyserLocale; import java.util.Collections; -public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command { +public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command { private final GeyserCommand command; /** @@ -59,13 +59,13 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement * @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); + public boolean canRun(CommandSourceStack source) { + return !requiresPermission() || source.hasPermission(GeyserFabricPermissions.RESTRICTED_MIN_LEVEL); } @Override public int run(CommandContext context) { - ServerCommandSource source = (ServerCommandSource) context.getSource(); + CommandSourceStack source = (CommandSourceStack) context.getSource(); FabricCommandSender sender = new FabricCommandSender(source); GeyserSession session = getGeyserSession(sender); if (!canRun(source)) { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java index d329c1894..942909068 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java @@ -27,11 +27,11 @@ package org.geysermc.geyser.platform.fabric.mixin.client; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; +import net.minecraft.client.server.IntegratedServer; +import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.text.Text; -import net.minecraft.world.GameMode; +import net.minecraft.world.level.GameType; import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter; import org.geysermc.geyser.text.GeyserLocale; @@ -46,25 +46,25 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(IntegratedServer.class) public class IntegratedServerMixin implements GeyserServerPortGetter { @Shadow - private int lanPort; + private int publishedPort; - @Shadow @Final private MinecraftClient client; + @Shadow @Final private Minecraft minecraft; - @Inject(method = "openToLan", at = @At("RETURN")) - private void onOpenToLan(GameMode gameMode, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) { + @Inject(method = "publishServer", at = @At("RETURN")) + private void onOpenToLan(GameType gameType, 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 - GeyserLocale.loadGeyserLocale(this.client.options.language); + GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode); // Give indication that Geyser is loaded - this.client.player.sendMessage(Text.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start", - this.client.options.language, "localhost", String.valueOf(this.lanPort))), false); + this.minecraft.player.displayClientMessage(Component.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start", + this.minecraft.options.languageCode, "localhost", String.valueOf(this.publishedPort))), false); } } @Override public int geyser$getServerPort() { - return this.lanPort; + return this.publishedPort; } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java index 799d94917..23e148775 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java @@ -26,26 +26,26 @@ package org.geysermc.geyser.platform.fabric.mixin.server; 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.ApiServices; -import net.minecraft.world.level.storage.LevelStorage; +import net.minecraft.server.Services; +import net.minecraft.server.WorldStem; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.progress.ChunkProgressListenerFactory; +import net.minecraft.server.packs.repository.PackRepository; +import net.minecraft.world.level.storage.LevelStorageSource; import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter; import org.spongepowered.asm.mixin.Mixin; import java.net.Proxy; -@Mixin(MinecraftDedicatedServer.class) +@Mixin(DedicatedServer.class) public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter { - 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); + public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) { + super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory); } @Override public int geyser$getServerPort() { - return this.getServerPort(); + return this.getPort(); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java index be68cefb9..0746198f3 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java @@ -29,15 +29,15 @@ 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.NbtList; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.ListTag; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.WritableBookItem; +import net.minecraft.world.item.WrittenBookItem; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.LecternBlockEntity; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; @@ -65,9 +65,9 @@ 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 = getPlayer(session); + ServerPlayer player = getPlayer(session); if (player != null) { - BlockEntity blockEntity = player.world.getBlockEntity(new BlockPos(x, y, z)); + BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z)); if (!(blockEntity instanceof LecternBlockEntity lectern)) { return; } @@ -83,14 +83,14 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { 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); + lecternTag.putInt("page", lectern.getPage() / 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.getNbt())) { - NbtList listTag = book.getNbt().getList("pages", 8); + if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) { + ListTag listTag = book.getTag().getList("pages", 8); for (int i = 0; i < listTag.size(); i++) { String page = listTag.getString(i); @@ -127,14 +127,14 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { // Workaround for our commands because fabric doesn't have native permissions for (GeyserFabricCommandExecutor executor : GeyserFabricMod.getInstance().getCommandExecutors()) { if (executor.getCommand().permission().equals(permission)) { - return executor.canRun(getPlayer(session).getCommandSource()); + return executor.canRun(getPlayer(session).createCommandSourceStack()); } } return false; } - private PlayerEntity getPlayer(GeyserSession session) { - return server.getPlayerManager().getPlayer(session.getPlayerEntity().getUuid()); + private ServerPlayer getPlayer(GeyserSession session) { + return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b4d7430f1..040ddbe62 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,6 @@ paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", versio # check these on https://modmuss50.me/fabric.html fabric-minecraft = { group = "com.mojang", name = "minecraft", version = "1.19.1" } -fabric-yarn = { group = "net.fabricmc", name = "yarn", version = "1.19.1+build.1" } fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version = "0.14.8" } fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version = "0.58.5+1.19.1" } From 730b0beb012a2890e76a70135ca9855ed6fa6f1b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 18 Oct 2022 16:05:55 -0400 Subject: [PATCH 227/290] Consolidate CommandManager implementations A lot of these just implemented the class overrode the `description` method returning nothing. --- .../bungeecord/GeyserBungeePlugin.java | 5 +-- .../command/GeyserBungeeCommandManager.java | 41 ------------------- .../platform/fabric/GeyserFabricMod.java | 5 +-- .../command/GeyserFabricCommandManager.java | 41 ------------------- .../standalone/GeyserStandaloneBootstrap.java | 5 +-- .../GeyserStandaloneCommandManager.java | 41 ------------------- .../standalone/gui/GeyserStandaloneGUI.java | 4 +- .../velocity/GeyserVelocityPlugin.java | 5 +-- .../command/GeyserVelocityCommandManager.java | 41 ------------------- .../geyser/command/GeyserCommandManager.java | 6 ++- 10 files changed, 14 insertions(+), 180 deletions(-) delete mode 100644 bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java delete mode 100644 bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java delete mode 100644 bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java delete mode 100644 bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index ab5531ba3..1c460f4de 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -43,7 +43,6 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor; -import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -62,7 +61,7 @@ import java.util.logging.Level; public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { - private GeyserBungeeCommandManager geyserCommandManager; + private GeyserCommandManager geyserCommandManager; private GeyserBungeeConfiguration geyserConfig; private GeyserBungeeInjector geyserInjector; private GeyserBungeeLogger geyserLogger; @@ -205,7 +204,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserInjector = new GeyserBungeeInjector(this); this.geyserInjector.initializeLocalChannel(this); - this.geyserCommandManager = new GeyserBungeeCommandManager(geyser); + this.geyserCommandManager = new GeyserCommandManager(geyser); this.geyserCommandManager.init(); this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands())); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java deleted file mode 100644 index e0fd7a4ac..000000000 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.bungeecord.command; - -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommandManager; - -public class GeyserBungeeCommandManager extends GeyserCommandManager { - - public GeyserBungeeCommandManager(GeyserImpl geyser) { - super(geyser); - } - - @Override - public String description(String command) { - return ""; // no support for command descriptions in bungee - } -} diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index 333a3d810..792e16788 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -49,7 +49,6 @@ import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; -import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandManager; import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -79,7 +78,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { private List playerCommands; private final List commandExecutors = new ArrayList<>(); - private GeyserFabricCommandManager geyserCommandManager; + private GeyserCommandManager geyserCommandManager; private GeyserFabricConfiguration geyserConfig; private GeyserFabricLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; @@ -176,7 +175,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); - this.geyserCommandManager = new GeyserFabricCommandManager(connector); + this.geyserCommandManager = new GeyserCommandManager(connector); this.geyserCommandManager.init(); this.geyserWorldManager = new GeyserFabricWorldManager(server); diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java deleted file mode 100644 index d21dae319..000000000 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.fabric.command; - -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommandManager; - -public class GeyserFabricCommandManager extends GeyserCommandManager { - - public GeyserFabricCommandManager(GeyserImpl connector) { - super(connector); - } - - @Override - public String description(String command) { - return ""; - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 80d17f6a7..5cbbab9d4 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -47,7 +47,6 @@ import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager; import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -64,7 +63,7 @@ import java.util.stream.Collectors; public class GeyserStandaloneBootstrap implements GeyserBootstrap { - private GeyserStandaloneCommandManager geyserCommandManager; + private GeyserCommandManager geyserCommandManager; private GeyserStandaloneConfiguration geyserConfig; private GeyserStandaloneLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; @@ -220,7 +219,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { geyser = GeyserImpl.load(PlatformType.STANDALONE, this); GeyserImpl.start(); - geyserCommandManager = new GeyserStandaloneCommandManager(geyser); + geyserCommandManager = new GeyserCommandManager(geyser); geyserCommandManager.init(); if (gui != null) { diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java deleted file mode 100644 index e7b4cbe37..000000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserStandaloneCommandManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.standalone.command; - -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommandManager; - -public class GeyserStandaloneCommandManager extends GeyserCommandManager { - - public GeyserStandaloneCommandManager(GeyserImpl geyser) { - super(geyser); - } - - @Override - public String description(String command) { - return ""; // this is not sent over the protocol, so we return none - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index a8bce303f..41cbafb25 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.platform.standalone.gui; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.command.GeyserCommand; +import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.platform.standalone.GeyserStandaloneLogger; -import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; @@ -256,7 +256,7 @@ public class GeyserStandaloneGUI { * @param geyserStandaloneLogger The current logger * @param geyserCommandManager The commands manager */ - public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserStandaloneCommandManager geyserCommandManager) { + public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) { commandsMenu.removeAll(); optionsMenu.removeAll(); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index e92bb6cf2..5ac09416c 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -48,7 +48,6 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor; -import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; import org.jetbrains.annotations.Nullable; @@ -75,7 +74,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Inject private CommandManager commandManager; - private GeyserVelocityCommandManager geyserCommandManager; + private GeyserCommandManager geyserCommandManager; private GeyserVelocityConfiguration geyserConfig; private GeyserVelocityInjector geyserInjector; private GeyserVelocityLogger geyserLogger; @@ -163,7 +162,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserInjector = new GeyserVelocityInjector(proxyServer); // Will be initialized after the proxy has been bound - this.geyserCommandManager = new GeyserVelocityCommandManager(geyser); + this.geyserCommandManager = new GeyserCommandManager(geyser); this.geyserCommandManager.init(); this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.getCommands())); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java deleted file mode 100644 index 6f9faba8f..000000000 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.velocity.command; - -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.command.GeyserCommandManager; - -public class GeyserVelocityCommandManager extends GeyserCommandManager { - - public GeyserVelocityCommandManager(GeyserImpl geyser) { - super(geyser); - } - - @Override - public String description(String command) { - return ""; // no support for command descriptions in velocity - } -} diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java index 7c5bd6580..d28f9d24e 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java @@ -63,7 +63,7 @@ import java.util.Locale; import java.util.Map; @RequiredArgsConstructor -public abstract class GeyserCommandManager { +public class GeyserCommandManager { @Getter private final Map commands = new Object2ObjectOpenHashMap<>(12); @@ -198,7 +198,9 @@ public abstract class GeyserCommandManager { * @param command Command to get the description for * @return Command description */ - public abstract String description(String command); + public String description(String command) { + return ""; + } @RequiredArgsConstructor public static class CommandBuilder implements Command.Builder { From 94a810b68346cd3986e9380cb528aba815c0e7dd Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:04:02 -0400 Subject: [PATCH 228/290] Initial 1.19.40.24 Bedrock support --- .../geysermc/geyser/level/JavaDimension.java | 4 +- .../geysermc/geyser/network/GameProtocol.java | 2 + .../translator/level/BiomeTranslator.java | 4 +- .../protocol/java/JavaLoginTranslator.java | 4 +- ...JavaCodecEntry.java => JavaCodecUtil.java} | 5 ++- .../geyser/util/StatisticFormatters.java | 9 +++-- .../geysermc/geyser/util/StatisticsUtils.java | 39 +++++++++---------- 7 files changed, 37 insertions(+), 30 deletions(-) rename core/src/main/java/org/geysermc/geyser/util/{JavaCodecEntry.java => JavaCodecUtil.java} (96%) diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java index 5f3c96b86..a3f6b55e4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.level; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; -import org.geysermc.geyser.util.JavaCodecEntry; +import org.geysermc.geyser.util.JavaCodecUtil; import java.util.Map; @@ -39,7 +39,7 @@ import java.util.Map; public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { public static void load(CompoundTag tag, Map map) { - for (CompoundTag dimension : JavaCodecEntry.iterateAsTag(tag.get("minecraft:dimension_type"))) { + for (CompoundTag dimension : JavaCodecUtil.iterateAsTag(tag.get("minecraft:dimension_type"))) { CompoundTag elements = dimension.get("element"); int minY = ((IntTag) elements.get("min_y")).getValue(); int maxY = ((IntTag) elements.get("height")).getValue(); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 844fd0f51..5870b92b6 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -33,6 +33,7 @@ import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import com.nukkitx.protocol.bedrock.v545.Bedrock_v545; import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; +import com.nukkitx.protocol.bedrock.v557.Bedrock_v557; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -75,6 +76,7 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.30/1.19.31") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); } /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index 3e47bfc37..04b39deeb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -45,7 +45,7 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.JavaCodecEntry; +import org.geysermc.geyser.util.JavaCodecUtil; import org.geysermc.geyser.util.MathUtils; // Array index formula by https://wiki.vg/Chunk_Format @@ -59,7 +59,7 @@ public class BiomeTranslator { ListTag serverBiomes = worldGen.get("value"); session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); - for (CompoundTag biomeTag : JavaCodecEntry.iterateAsTag(worldGen)) { + for (CompoundTag biomeTag : JavaCodecUtil.iterateAsTag(worldGen)) { String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); int javaId = ((IntTag) biomeTag.get("id")).getValue(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 978d4b6fb..60382e17a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -46,7 +46,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; -import org.geysermc.geyser.util.JavaCodecEntry; +import org.geysermc.geyser.util.JavaCodecUtil; import org.geysermc.geyser.util.PluginMessageUtils; import java.util.Map; @@ -66,7 +66,7 @@ public class JavaLoginTranslator extends PacketTranslator chatTypes = session.getChatTypes(); chatTypes.clear(); - for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { + for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. int id = ((IntTag) tag.get("id")).getValue(); CompoundTag element = tag.get("element"); diff --git a/core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java b/core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java similarity index 96% rename from core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java rename to core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java index 45be5bf99..f0b8ee6bc 100644 --- a/core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java +++ b/core/src/main/java/org/geysermc/geyser/util/JavaCodecUtil.java @@ -32,7 +32,7 @@ import com.github.steveice10.opennbt.tag.builtin.Tag; import javax.annotation.Nonnull; import java.util.Iterator; -public record JavaCodecEntry() { +public final class JavaCodecUtil { /** * Iterate over a Java Edition codec and return each entry as a CompoundTag @@ -58,4 +58,7 @@ public record JavaCodecEntry() { } }; } + + private JavaCodecUtil() { + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java index 7e1f6e7b7..d46a759fe 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java @@ -26,17 +26,17 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.statistic.StatisticFormat; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.EnumMap; import java.util.Locale; import java.util.Map; import java.util.function.IntFunction; -public class StatisticFormatters { +public final class StatisticFormatters { - private static final Map> FORMATTERS = new Object2ObjectOpenHashMap<>(); + private static final Map> FORMATTERS = new EnumMap<>(StatisticFormat.class); private static final DecimalFormat FORMAT = new DecimalFormat("###,###,##0.00"); public static final IntFunction INTEGER = NumberFormat.getIntegerInstance(Locale.US)::format; @@ -78,4 +78,7 @@ public class StatisticFormatters { public static IntFunction get(StatisticFormat format) { return FORMATTERS.getOrDefault(format, INTEGER); } + + private StatisticFormatters() { + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index f01670106..58e0b131a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.statistic.*; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.util.FormImage; import org.geysermc.geyser.registry.BlockRegistries; @@ -37,7 +38,6 @@ import org.geysermc.geyser.text.MinecraftLocale; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.function.IntFunction; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -79,23 +79,23 @@ public class StatisticsUtils { case 0: builder.title("stat.generalButton"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof CustomStatistic statistic) { String statName = statistic.name().toLowerCase(Locale.ROOT); IntFunction formatter = StatisticFormatters.get(statistic.getFormat()); - content.add("stat.minecraft." + statName + ": " + formatter.apply(entry.getValue())); + content.add("stat.minecraft." + statName + ": " + formatter.apply(entry.getIntValue())); } } break; case 1: builder.title("stat.itemsButton - stat_type.minecraft.mined"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof BreakBlockStatistic statistic) { String identifier = BlockRegistries.CLEAN_JAVA_IDENTIFIERS.get(statistic.getId()); if (identifier != null) { String block = identifier.replace("minecraft:", "block.minecraft."); - content.add(block + ": " + entry.getValue()); + content.add(block + ": " + entry.getIntValue()); } } } @@ -103,71 +103,70 @@ public class StatisticsUtils { case 2: builder.title("stat.itemsButton - stat_type.minecraft.broken"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof BreakItemStatistic statistic) { String item = mappings.getMapping(statistic.getId()).getJavaIdentifier(); - content.add(getItemTranslateKey(item, language) + ": " + entry.getValue()); + content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } break; case 3: builder.title("stat.itemsButton - stat_type.minecraft.crafted"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof CraftItemStatistic statistic) { String item = mappings.getMapping(statistic.getId()).getJavaIdentifier(); - content.add(getItemTranslateKey(item, language) + ": " + entry.getValue()); + content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } break; case 4: builder.title("stat.itemsButton - stat_type.minecraft.used"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof UseItemStatistic statistic) { String item = mappings.getMapping(statistic.getId()).getJavaIdentifier(); - content.add(getItemTranslateKey(item, language) + ": " + entry.getValue()); + content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } break; case 5: builder.title("stat.itemsButton - stat_type.minecraft.picked_up"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof PickupItemStatistic statistic) { String item = mappings.getMapping(statistic.getId()).getJavaIdentifier(); - content.add(getItemTranslateKey(item, language) + ": " + entry.getValue()); + content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } break; case 6: builder.title("stat.itemsButton - stat_type.minecraft.dropped"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof DropItemStatistic statistic) { String item = mappings.getMapping(statistic.getId()).getJavaIdentifier(); - content.add(getItemTranslateKey(item, language) + ": " + entry.getValue()); + content.add(getItemTranslateKey(item, language) + ": " + entry.getIntValue()); } } break; case 7: builder.title("stat.mobsButton - geyser.statistics.killed"); - for (Map.Entry entry : session.getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof KillEntityStatistic statistic) { String entityName = statistic.getEntity().name().toLowerCase(Locale.ROOT); - content.add("entity.minecraft." + entityName + ": " + entry.getValue()); + content.add("entity.minecraft." + entityName + ": " + entry.getIntValue()); } } break; case 8: builder.title("stat.mobsButton - geyser.statistics.killed_by"); - for (Map.Entry entry : session - .getStatistics().entrySet()) { + for (Object2IntMap.Entry entry : session.getStatistics().object2IntEntrySet()) { if (entry.getKey() instanceof KilledByEntityStatistic statistic) { String entityName = statistic.getEntity().name().toLowerCase(Locale.ROOT); - content.add("entity.minecraft." + entityName + ": " + entry.getValue()); + content.add("entity.minecraft." + entityName + ": " + entry.getIntValue()); } } break; From ece1b2a8ce2010fa947a32fde29b50910f08db26 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:04:45 -0400 Subject: [PATCH 229/290] Include versions TOML file change --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 040ddbe62..b16812b6f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.80.Final" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "2.9.12-20220926.095446-6" +protocol = "2.9.13-20221018.122404-1" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" mcprotocollib = "9f78bd5" @@ -79,7 +79,7 @@ junit = { group = "junit", name = "junit", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcprotocollib = { group = "com.github.GeyserMC", name = "MCProtocolLib", version.ref = "mcprotocollib" } packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" } -protocol = { group = "com.nukkitx.protocol", name = "bedrock-v554", version.ref = "protocol" } +protocol = { group = "com.nukkitx.protocol", name = "bedrock-v557", version.ref = "protocol" } raknet = { group = "com.nukkitx.network", name = "raknet", version.ref = "raknet" } sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } From e8764c6a817cebde1e508e3ffe613d459d1702fe Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Thu, 20 Oct 2022 20:17:08 +0200 Subject: [PATCH 230/290] Fix rare NPE in skin handling code (#3357) --- .../org/geysermc/geyser/skin/SkinManager.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 992835a2b..730d46908 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java @@ -258,21 +258,26 @@ public class SkinManager { JsonNode skinObject = GeyserImpl.JSON_MAPPER.readTree(new String(Base64.getDecoder().decode(encodedJson), StandardCharsets.UTF_8)); JsonNode textures = skinObject.get("textures"); - if (textures != null) { - JsonNode skinTexture = textures.get("SKIN"); - String skinUrl = skinTexture.get("url").asText().replace("http://", "https://"); - - boolean isAlex = skinTexture.has("metadata"); - - String capeUrl = null; - JsonNode capeTexture = textures.get("CAPE"); - if (capeTexture != null) { - capeUrl = capeTexture.get("url").asText().replace("http://", "https://"); - } - - return new GameProfileData(skinUrl, capeUrl, isAlex); + if (textures == null) { + return null; } - return null; + + JsonNode skinTexture = textures.get("SKIN"); + if (skinTexture == null) { + return null; + } + + String skinUrl = skinTexture.get("url").asText().replace("http://", "https://"); + + boolean isAlex = skinTexture.has("metadata"); + + String capeUrl = null; + JsonNode capeTexture = textures.get("CAPE"); + if (capeTexture != null) { + capeUrl = capeTexture.get("url").asText().replace("http://", "https://"); + } + + return new GameProfileData(skinUrl, capeUrl, isAlex); } /** From a612be60aada1f4e931420d9823bc02df40dcbd3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:09:17 -0400 Subject: [PATCH 231/290] Warn when custom item name begins with a digit --- .../registry/populator/CustomItemRegistryPopulator.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 1daa6d28d..94e04e972 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -66,6 +66,13 @@ public class CustomItemRegistryPopulator { if (!item.customItemOptions().hasCustomItemOptions()) { GeyserImpl.getInstance().getLogger().error("The custom item " + item.name() + " has no registration types"); } + String name = item.name(); + if (name.isEmpty()) { + GeyserImpl.getInstance().getLogger().warning("Custom item name is empty?"); + } else if (Character.isDigit(name.charAt(0))) { + // As of 1.19.31 + GeyserImpl.getInstance().getLogger().warning("Custom item name (" + name + ") begins with a digit. This may cause issues!"); + } return true; } From 254f0da03cdeb213dfea36eae0559e76852b6ae7 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:21:02 -0400 Subject: [PATCH 232/290] Fabric improvements Mainly in commands - the old permissions file no longer needs to exist. --- bootstrap/fabric/build.gradle.kts | 3 + .../platform/fabric/GeyserFabricLogger.java | 14 +++- .../platform/fabric/GeyserFabricMod.java | 74 +++++-------------- ...s.java => GeyserFabricUpdateListener.java} | 31 +++----- .../fabric/command/FabricCommandSender.java | 26 ++++--- .../command/GeyserFabricCommandExecutor.java | 35 ++------- .../world/GeyserFabricWorldManager.java | 13 +--- .../fabric/src/main/resources/fabric.mod.json | 3 +- .../fabric/src/main/resources/permissions.yml | 13 ---- .../org/geysermc/geyser/text/ChatColor.java | 18 +---- gradle/libs.versions.toml | 9 ++- 11 files changed, 81 insertions(+), 158 deletions(-) rename bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/{GeyserFabricPermissions.java => GeyserFabricUpdateListener.java} (65%) delete mode 100644 bootstrap/fabric/src/main/resources/permissions.yml diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index dac791173..02f24bba5 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -19,6 +19,9 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation(libs.fabric.api) + // This should be in the libs TOML, but something about modImplementation AND include just doesn't work + include(modImplementation("me.lucko", "fabric-permissions-api", "0.2-SNAPSHOT")) + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java index a6ee77f41..180197f2d 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java @@ -25,12 +25,14 @@ package org.geysermc.geyser.platform.fabric; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.text.ChatColor; public class GeyserFabricLogger implements GeyserLogger { - private final Logger logger = LogManager.getLogger("geyser-fabric"); private boolean debug; @@ -69,6 +71,16 @@ public class GeyserFabricLogger implements GeyserLogger { logger.info(message); } + @Override + public void sendMessage(Component message) { + // As of Java Edition 1.19.2, Fabric's console doesn't natively support legacy format + String flattened = LegacyComponentSerializer.legacySection().serialize(message); + // Add the reset at the end, or else format will persist... forever. + // https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png + String text = ChatColor.toANSI(flattened) + ChatColor.ANSI_RESET; + info(text); + } + @Override public void debug(String message) { if (debug) { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index 792e16788..1e9543ff8 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -29,6 +29,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.commands.CommandSourceStack; @@ -55,29 +56,21 @@ import org.geysermc.geyser.util.FileUtils; 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.*; public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { - private static GeyserFabricMod instance; private boolean reloading; - private GeyserImpl connector; + private GeyserImpl geyser; private ModContainer mod; private Path dataFolder; private MinecraftServer server; - /** - * Commands that don't require any permission level to ran - */ - private List playerCommands; - private final List commandExecutors = new ArrayList<>(); - private GeyserCommandManager geyserCommandManager; private GeyserFabricConfiguration geyserConfig; private GeyserFabricLogger geyserLogger; @@ -111,8 +104,6 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); - 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(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); @@ -123,10 +114,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + this.geyser = GeyserImpl.load(PlatformType.FABRIC, this); + if (server == null) { // Server has yet to start // Register onDisable so players are properly kicked ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable()); + + ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler)); } else { // Server has started and this is a reload startGeyser(this.server); @@ -170,38 +165,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { geyserConfig.loadFloodgate(this, floodgate.orElse(null)); - this.connector = GeyserImpl.load(PlatformType.FABRIC, this); - GeyserImpl.start(); // shrug + GeyserImpl.start(); - this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); - this.geyserCommandManager = new GeyserCommandManager(connector); + this.geyserCommandManager = new GeyserCommandManager(geyser); this.geyserCommandManager.init(); this.geyserWorldManager = new GeyserFabricWorldManager(server); // Start command building // Set just "geyser" as the help command - GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(connector, - (GeyserCommand) connector.commandManager().getCommands().get("help"), !playerCommands.contains("help")); - commandExecutors.add(helpExecutor); + GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser, + (GeyserCommand) geyser.commandManager().getCommands().get("help")); LiteralArgumentBuilder builder = Commands.literal("geyser").executes(helpExecutor); // Register all subcommands as valid - 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(Commands.literal(command.getKey()).executes(executor)); + for (Map.Entry command : geyser.commandManager().getCommands().entrySet()) { + GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue()); + builder.then(Commands.literal(command.getKey()) + .executes(executor) + // Could also test for Bedrock but depending on when this is called it may backfire + .requires(executor::testPermission)); } server.getCommands().getDispatcher().register(builder); } @Override public void onDisable() { - if (connector != null) { - connector.shutdown(); - connector = null; + if (geyser != null) { + geyser.shutdown(); + geyser = null; } if (!reloading) { this.server = null; @@ -267,34 +261,6 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { this.reloading = reloading; } - private File fileOrCopiedFromResource(File file, String name) throws IOException { - if (!file.exists()) { - //noinspection ResultOfMethodCallIgnored - file.createNewFile(); - FileOutputStream fos = new FileOutputStream(file); - InputStream input = getResource(name); - - 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; - } - - public List getCommandExecutors() { - return commandExecutors; - } - public static GeyserFabricMod getInstance() { return instance; } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java similarity index 65% rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java rename to bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java index a625f6d1f..1ea69cbe2 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPermissions.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java @@ -25,26 +25,19 @@ package org.geysermc.geyser.platform.fabric; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; +import me.lucko.fabric.api.permissions.v0.Permissions; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import org.geysermc.geyser.Constants; +import org.geysermc.geyser.platform.fabric.command.FabricCommandSender; +import org.geysermc.geyser.util.VersionCheckUtils; -/** - * A class outline of the permissions.yml file - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class GeyserFabricPermissions { +public final class GeyserFabricUpdateListener { + public static void onPlayReady(ServerGamePacketListenerImpl handler) { + if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) { + VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack())); + } + } - /** - * 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; - - public String[] getCommands() { - return this.commands; + private GeyserFabricUpdateListener() { } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java index 0bb171e6b..5973e04f1 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java @@ -25,12 +25,13 @@ package org.geysermc.geyser.platform.fabric.command; +import me.lucko.fabric.api.permissions.v0.Permissions; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandSource; -import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.text.ChatColor; import javax.annotation.Nonnull; @@ -57,22 +58,23 @@ public class FabricCommandSender implements GeyserCommandSource { } } + @Override + public void sendMessage(net.kyori.adventure.text.Component message) { + if (source.getEntity() instanceof ServerPlayer player) { + String decoded = GsonComponentSerializer.gson().serialize(message); + player.displayClientMessage(Component.Serializer.fromJson(decoded), false); + return; + } + GeyserCommandSource.super.sendMessage(message); + } + @Override public boolean isConsole() { return !(source.getEntity() instanceof ServerPlayer); } @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().permission().equals(s)) { - return executor.canRun(source); - } - } - - return false; + public boolean hasPermission(String permission) { + return Permissions.check(source, permission); } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java index f691cd49e..7600e4136 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java @@ -27,12 +27,12 @@ package org.geysermc.geyser.platform.fabric.command; import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; +import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.commands.CommandSourceStack; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.platform.fabric.GeyserFabricMod; -import org.geysermc.geyser.platform.fabric.GeyserFabricPermissions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; @@ -40,27 +40,15 @@ import org.geysermc.geyser.text.GeyserLocale; import java.util.Collections; public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command { - private final GeyserCommand command; - /** - * Whether the command requires an OP permission level of 2 or greater - */ - private final boolean requiresPermission; - public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command, boolean requiresPermission) { + public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) { super(connector, Collections.singletonMap(command.name(), command)); this.command = command; - 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(CommandSourceStack source) { - return !requiresPermission() || source.hasPermission(GeyserFabricPermissions.RESTRICTED_MIN_LEVEL); + public boolean testPermission(CommandSourceStack source) { + return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0); } @Override @@ -68,8 +56,8 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement CommandSourceStack source = (CommandSourceStack) context.getSource(); FabricCommandSender sender = new FabricCommandSender(source); GeyserSession session = getGeyserSession(sender); - if (!canRun(source)) { - sender.sendMessage(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")); + if (!testPermission(source)) { + sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); return 0; } if (this.command.name().equals("reload")) { @@ -83,15 +71,4 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement 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/geyser/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java index 0746198f3..eb4f61c67 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java @@ -29,6 +29,7 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; +import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.core.BlockPos; import net.minecraft.nbt.ListTag; import net.minecraft.server.MinecraftServer; @@ -39,8 +40,6 @@ import net.minecraft.world.item.WrittenBookItem; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity; import org.geysermc.geyser.level.GeyserWorldManager; -import org.geysermc.geyser.platform.fabric.GeyserFabricMod; -import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.util.BlockEntityUtils; @@ -124,14 +123,8 @@ 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().permission().equals(permission)) { - return executor.canRun(getPlayer(session).createCommandSourceStack()); - } - } - - return false; + ServerPlayer player = getPlayer(session); + return Permissions.check(player, permission); } private ServerPlayer getPlayer(GeyserSession session) { diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index ee23dd06d..98a410950 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,6 +25,7 @@ "depends": { "fabricloader": ">=0.14.8", "fabric": "*", - "minecraft": ">=1.19" + "minecraft": ">=1.19", + "fabric-permissions-api-v0": "*" } } diff --git a/bootstrap/fabric/src/main/resources/permissions.yml b/bootstrap/fabric/src/main/resources/permissions.yml deleted file mode 100644 index ae20447ed..000000000 --- a/bootstrap/fabric/src/main/resources/permissions.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Uncomment any commands that you wish to be run by clients -# Commented commands require an OP permission of 2 or greater -commands: - - help - - advancements - - statistics - - settings - - offhand - - tooltips -# - list -# - reload -# - version -# - dump diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java index d39c0d696..49178f033 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.text; public class ChatColor { + public static final String ANSI_RESET = (char) 0x1b + "[0m"; public static final char ESCAPE = '§'; public static final String BLACK = ESCAPE + "0"; @@ -64,7 +65,7 @@ public class ChatColor { string = string.replace(ITALIC, (char) 0x1b + "[3m"); string = string.replace(UNDERLINE, (char) 0x1b + "[4m"); string = string.replace(STRIKETHROUGH, (char) 0x1b + "[9m"); - string = string.replace(RESET, (char) 0x1b + "[0m"); + string = string.replace(RESET, ANSI_RESET); string = string.replace(BLACK, (char) 0x1b + "[0;30m"); string = string.replace(DARK_BLUE, (char) 0x1b + "[0;34m"); string = string.replace(DARK_GREEN, (char) 0x1b + "[0;32m"); @@ -83,19 +84,4 @@ public class ChatColor { string = string.replace(WHITE, (char) 0x1b + "[37;1m"); return string; } - - public String translateAlternateColorCodes(char color, String message) { - return message.replace(color, ESCAPE); - } - - /** - * Remove all colour formatting tags from a message - * - * @param message Message to remove colour tags from - * - * @return The sanitised message - */ - public static String stripColors(String message) { - return message = message.replaceAll("(&([a-fk-or0-9]))","").replaceAll("(§([a-fk-or0-9]))","").replaceAll("s/\\x1b\\[[0-9;]*[a-zA-Z]//g",""); - } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b16812b6f..4e2efe00b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,9 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.0.0" sponge = "8.0.0" +fabric-minecraft = "1.19.1" +fabric-loader = "0.14.8" +fabric-api = "0.58.5+1.19.1" [libraries] jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } @@ -63,9 +66,9 @@ paper-api = { group = "io.papermc.paper", name = "paper-api", version.ref = "pap paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "paper" } # check these on https://modmuss50.me/fabric.html -fabric-minecraft = { group = "com.mojang", name = "minecraft", version = "1.19.1" } -fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version = "0.14.8" } -fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version = "0.58.5+1.19.1" } +fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" } +fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" } +fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" } adapters-spigot = { group = "org.geysermc.geyser.adapters", name = "spigot-all", version.ref = "adapters" } bungeecord-proxy = { group = "com.github.SpigotMC.BungeeCord", name = "bungeecord-proxy", version.ref = "bungeecord" } From ca7799d984abfbdaa9d467f132ed8ec7261d3170 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:26:28 -0400 Subject: [PATCH 233/290] Add core Gradle Adventure change --- core/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1ab99990a..994325ea0 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -51,7 +51,7 @@ dependencies { implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } } // Adventure text serialization - implementation(libs.bundles.adventure) + api(libs.bundles.adventure) // Test testImplementation(libs.junit) From e9b99b209814d43573e7c74712ccc165b9d6a1f3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 25 Oct 2022 16:49:34 -0400 Subject: [PATCH 234/290] Indicate 1.19.40 support; bump Protocol --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 8 +++----- gradle/libs.versions.toml | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d91672eb4..a28ba8eb0 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.30/1.19.31 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.40 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 5870b92b6..7bba6bb89 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -48,9 +48,7 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v554.V554_CODEC.toBuilder() - .minecraftVersion("1.19.31") - .build(); + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v557.V557_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -73,10 +71,10 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder() .minecraftVersion("1.19.30/1.19.31") .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e2efe00b..3724836d9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.80.Final" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "2.9.13-20221018.122404-1" +protocol = "2.9.14-20221025.193624-1" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" mcprotocollib = "9f78bd5" From 0d3b77e56793d2e5c2012ff1f5d8c6253a43db5c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 26 Oct 2022 17:57:40 -0400 Subject: [PATCH 235/290] Fix chunk translation errors in online mode --- .../geyser/translator/protocol/java/JavaLoginTranslator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 60382e17a..d48d78439 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -105,6 +105,10 @@ public class JavaLoginTranslator extends PacketTranslator Date: Sat, 29 Oct 2022 20:08:41 -0400 Subject: [PATCH 236/290] Fix bounding box for 1.19.40 after death + respawn (#3374) Co-authored-by: onebeastchris <105284508+onebeastchris@users.noreply.github.com> --- .../geyser/entity/type/player/SessionPlayerEntity.java | 10 ++++++++++ .../bedrock/entity/player/BedrockActionTranslator.java | 3 +++ 2 files changed, 13 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index 7a5d34973..74b95b73c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -120,6 +120,16 @@ public class SessionPlayerEntity extends PlayerEntity { refreshSpeed = true; } + /** + * Since 1.19.40, the client must be re-informed of its bounding box on respawn + * See https://github.com/GeyserMC/Geyser/issues/3370 + */ + public void updateBoundingBox() { + dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, getBoundingBoxHeight()); + dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, getBoundingBoxWidth()); + updateBedrockMetadata(); + } + @Override public boolean setBoundingBoxHeight(float height) { if (super.setBoundingBoxHeight(height)) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java index 72f064a55..c728390d6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java @@ -75,6 +75,9 @@ public class BedrockActionTranslator extends PacketTranslator Date: Sun, 30 Oct 2022 12:28:48 -0400 Subject: [PATCH 237/290] Prevent large Object[] allocations in command list translation --- .../geyser/translator/protocol/java/JavaCommandsTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 3fa43c788..8f4e46454 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -137,7 +137,7 @@ public class JavaCommandsTranslator extends PacketTranslator= 1) { for (int childIndex : node.getChildIndices()) { - commandArgs.computeIfAbsent(nodeIndex, ArrayList::new).add(nodes[childIndex]); + commandArgs.computeIfAbsent(nodeIndex, ($) -> new ArrayList<>()).add(nodes[childIndex]); } } From 87f8cf9ceaa506c37f6e6f84b68c1056e629a881 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 30 Oct 2022 12:31:46 -0400 Subject: [PATCH 238/290] Update mappings to fix bow sounds (#3375) Fixes #3311 --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index f1c9c2fbb..10baa9a45 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit f1c9c2fbba0e102dc4f8c96dd9485f7ec9768174 +Subproject commit 10baa9a45de074afa643e8477bd5a4e72ecfa563 From 592b48dbf5fa807cf09e04909a0054a1daaf9567 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 1 Nov 2022 09:59:44 -0400 Subject: [PATCH 239/290] Simplify IP censoring in dumps (#3330) --- .../bungeecord/GeyserBungeeDumpInfo.java | 15 +++-- bootstrap/fabric/build.gradle.kts | 3 - .../platform/fabric/GeyserFabricDumpInfo.java | 57 +++++++--------- .../platform/fabric/GeyserFabricMod.java | 5 +- .../geyser/platform/fabric/ModInfo.java | 66 ------------------- .../platform/spigot/GeyserSpigotDumpInfo.java | 9 +-- .../platform/sponge/GeyserSpongeDumpInfo.java | 9 +-- .../velocity/GeyserVelocityDumpInfo.java | 9 +-- .../geyser/dump/BootstrapDumpInfo.java | 3 + .../geyser/text/AsteriskSerializer.java | 12 ++-- 10 files changed, 56 insertions(+), 132 deletions(-) delete mode 100644 bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java index 2278d99d9..ba7bc464f 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java @@ -29,7 +29,6 @@ import lombok.Getter; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.plugin.Plugin; import org.geysermc.geyser.dump.BootstrapDumpInfo; -import org.geysermc.geyser.text.AsteriskSerializer; import java.util.ArrayList; import java.util.Collections; @@ -52,15 +51,17 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo { this.plugins = new ArrayList<>(); for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) { - String hostname = listener.getHost().getHostString(); - if (!AsteriskSerializer.showSensitive && !(hostname.equals("") || hostname.equals("0.0.0.0"))) { - hostname = "***"; - } - this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort())); + this.listeners.add(new ListenerInfo(listener.getHost().getHostString(), listener.getHost().getPort())); } for (Plugin plugin : proxy.getPluginManager().getPlugins()) { - this.plugins.add(new PluginInfo(true, plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), Collections.singletonList(plugin.getDescription().getAuthor()))); + this.plugins.add(new PluginInfo( + true, + plugin.getDescription().getName(), + plugin.getDescription().getVersion(), + plugin.getDescription().getMain(), + Collections.singletonList(plugin.getDescription().getAuthor())) + ); } } } diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 02f24bba5..743b75a26 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -1,8 +1,5 @@ plugins { id("fabric-loom") version "1.0-SNAPSHOT" - id("maven-publish") - id("com.github.johnrengelman.shadow") - id("java") } java { diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java index 2db6a3729..ee986ee62 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java @@ -25,65 +25,58 @@ package org.geysermc.geyser.platform.fabric; +import lombok.AllArgsConstructor; +import lombok.Getter; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.api.metadata.ModMetadata; +import net.fabricmc.loader.api.metadata.Person; import net.minecraft.server.MinecraftServer; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.text.AsteriskSerializer; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; -@SuppressWarnings("unused") // The way that the dump renders makes them used +@Getter public class GeyserFabricDumpInfo extends BootstrapDumpInfo { private String platformVersion = null; private final EnvType environmentType; + @AsteriskSerializer.Asterisk(isIp = true) 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; - } - } + FabricLoader.getInstance().getModContainer("fabricloader").ifPresent(mod -> + this.platformVersion = mod.getMetadata().getVersion().getFriendlyString()); + this.environmentType = FabricLoader.getInstance().getEnvironmentType(); - if (AsteriskSerializer.showSensitive || (server.getLocalIp() == null || server.getLocalIp().equals("") || server.getLocalIp().equals("0.0.0.0"))) { - this.serverIP = server.getLocalIp(); - } else { - this.serverIP = "***"; - } + this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp(); this.serverPort = server.getPort(); this.mods = new ArrayList<>(); for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - this.mods.add(new ModInfo(mod)); + ModMetadata meta = mod.getMetadata(); + this.mods.add(new ModInfo( + FabricLoader.getInstance().isModLoaded(meta.getId()), + meta.getId(), + meta.getVersion().getFriendlyString(), + meta.getAuthors().stream().map(Person::getName).collect(Collectors.toList())) + ); } } - public String getPlatformVersion() { - return platformVersion; - } - - public EnvType getEnvironmentType() { - return environmentType; - } - - public String getServerIP() { - return this.serverIP; - } - - public int getServerPort() { - return this.serverPort; - } - - public List getMods() { - return this.mods; + @Getter + @AllArgsConstructor + public static class ModInfo { + public boolean enabled; + public String name; + public String version; + public List authors; } } diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index 1e9543ff8..e5ff4b577 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -246,7 +246,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @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); + Path path = this.mod.findPath(resource).orElse(null); + if (path == null) { + return null; + } try { return path.getFileSystem() diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java deleted file mode 100644 index b9137c438..000000000 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModInfo.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.platform.fabric; - -import net.fabricmc.loader.api.ModContainer; - -import java.util.ArrayList; -import java.util.List; - -/** - * A wrapper for Fabric mod information to be presented in a Geyser dump - */ -public class ModInfo { - - 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(); - 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(); - } - - 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/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java index 92c2fe16b..d340935b3 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java @@ -41,6 +41,8 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo { private final String platformVersion; private final String platformAPIVersion; private final boolean onlineMode; + + @AsteriskSerializer.Asterisk(isIp = true) private final String serverIP; private final int serverPort; private final List plugins; @@ -51,12 +53,7 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo { this.platformVersion = Bukkit.getVersion(); this.platformAPIVersion = Bukkit.getBukkitVersion(); this.onlineMode = Bukkit.getOnlineMode(); - String ip = Bukkit.getIp(); - if (AsteriskSerializer.showSensitive || (ip.equals("") || ip.equals("0.0.0.0"))) { - this.serverIP = ip; - } else { - this.serverIP = "***"; - } + this.serverIP = Bukkit.getIp(); this.serverPort = Bukkit.getPort(); this.plugins = new ArrayList<>(); diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java index fc1bff3ef..628c85fd1 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java @@ -45,6 +45,8 @@ public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { private final String platformName; private final String platformVersion; private final boolean onlineMode; + + @AsteriskSerializer.Asterisk(isIp = true) private final String serverIP; private final int serverPort; private final List plugins; @@ -56,12 +58,7 @@ public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { this.platformVersion = platformMeta.version().getQualifier(); this.onlineMode = Sponge.server().isOnlineModeEnabled(); Optional socketAddress = Sponge.server().boundAddress(); - String hostString = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown"); - if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0") || hostString.equals("unknown"))) { - this.serverIP = hostString; - } else { - this.serverIP = "***"; - } + this.serverIP = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown"); this.serverPort = socketAddress.map(InetSocketAddress::getPort).orElse(-1); this.plugins = new ArrayList<>(); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java index b2765d3b2..45eb7abb9 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java @@ -41,6 +41,8 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo { private final String platformVersion; private final String platformVendor; private final boolean onlineMode; + + @AsteriskSerializer.Asterisk(isIp = true) private final String serverIP; private final int serverPort; private final List plugins; @@ -51,12 +53,7 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo { this.platformVersion = proxy.getVersion().getVersion(); this.platformVendor = proxy.getVersion().getVendor(); this.onlineMode = proxy.getConfiguration().isOnlineMode(); - String hostString = proxy.getBoundAddress().getHostString(); - if (AsteriskSerializer.showSensitive || (hostString.equals("") || hostString.equals("0.0.0.0"))) { - this.serverIP = hostString; - } else { - this.serverIP = "***"; - } + this.serverIP = proxy.getBoundAddress().getHostString(); this.serverPort = proxy.getBoundAddress().getPort(); this.plugins = new ArrayList<>(); diff --git a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java index 0bbc1c0ed..fda0566fd 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java @@ -29,6 +29,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.text.AsteriskSerializer; import java.util.List; @@ -53,6 +54,8 @@ public class BootstrapDumpInfo { @Getter @AllArgsConstructor public static class ListenerInfo { + + @AsteriskSerializer.Asterisk(isIp = true) public String ip; public int port; } diff --git a/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java b/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java index 27b277c72..69dbb558e 100644 --- a/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java +++ b/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java @@ -43,6 +43,8 @@ import java.util.Optional; public class AsteriskSerializer extends StdSerializer implements ContextualSerializer { + public static final String[] NON_SENSITIVE_ADDRESSES = {"", "0.0.0.0", "localhost", "127.0.0.1", "auto", "unknown"}; + public static boolean showSensitive = false; @Target({ElementType.FIELD}) @@ -91,11 +93,11 @@ public class AsteriskSerializer extends StdSerializer implements Context } private boolean isSensitiveIp(String ip) { - if (ip.equalsIgnoreCase("localhost") || ip.equalsIgnoreCase("auto")) { - // `auto` should not be shown unless there is an obscure issue with setting the localhost address - return false; + for (String address : NON_SENSITIVE_ADDRESSES) { + if (address.equalsIgnoreCase(ip)) { + return false; + } } - - return !ip.isEmpty() && !ip.equals("0.0.0.0") && !ip.equals("127.0.0.1"); + return true; } } From b1d832ddedf724165f9a2c6c4afad9f020c33550 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Wed, 9 Nov 2022 11:12:12 -0500 Subject: [PATCH 240/290] Replace ; with : in motd/submotd (#3389) --- .../network/ConnectorServerEventHandler.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index c9a3201c1..49fe6c42d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -125,13 +125,9 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { pong.setSubMotd(config.getBedrock().secondaryMotd()); } - if (config.isPassthroughPlayerCounts() && pingInfo != null) { - pong.setPlayerCount(pingInfo.getPlayers().getOnline()); - pong.setMaximumPlayerCount(pingInfo.getPlayers().getMax()); - } else { - pong.setPlayerCount(geyser.getSessionManager().getSessions().size()); - pong.setMaximumPlayerCount(config.getMaxPlayers()); - } + // https://github.com/GeyserMC/Geyser/issues/3388 + pong.setMotd(pong.getMotd().replace(';', ':')); + pong.setSubMotd(pong.getSubMotd().replace(';', ':')); // Fallbacks to prevent errors and allow Bedrock to see the server if (pong.getMotd() == null || pong.getMotd().isBlank()) { @@ -160,6 +156,14 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { } } + if (config.isPassthroughPlayerCounts() && pingInfo != null) { + pong.setPlayerCount(pingInfo.getPlayers().getOnline()); + pong.setMaximumPlayerCount(pingInfo.getPlayers().getMax()); + } else { + pong.setPlayerCount(geyser.getSessionManager().getSessions().size()); + pong.setMaximumPlayerCount(config.getMaxPlayers()); + } + //Bedrock will not even attempt a connection if the client thinks the server is full //so we have to fake it not being full if (pong.getPlayerCount() >= pong.getMaximumPlayerCount()) { From 7d84928627e94aab7b91d1aabc757371f48c8339 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 11 Nov 2022 11:10:08 -0500 Subject: [PATCH 241/290] (Should) remove unneeded messages about incorrect chunk heights --- .../translator/protocol/java/JavaLoginTranslator.java | 8 ++------ .../protocol/java/JavaRespawnTranslator.java | 3 +++ .../java/org/geysermc/geyser/util/ChunkUtils.java | 11 +++-------- .../java/org/geysermc/geyser/util/DimensionUtils.java | 8 ++++++-- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index d48d78439..ea0de7851 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -99,16 +99,10 @@ public class JavaLoginTranslator extends PacketTranslator BedrockDimension.THE_END; - case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; - default -> BedrockDimension.OVERWORLD; - }; - session.getChunkCache().setBedrockDimension(bedrockDimension); - + BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); // Yell in the console if the world height is too height in the current scenario // The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled // (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ ) diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index 59f5ed55d..5989b4e9d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -32,6 +32,7 @@ import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.session.GeyserSession; import java.util.Set; @@ -94,8 +95,11 @@ public class DimensionUtils { changeDimensionPacket.setPosition(pos); session.sendUpstreamPacket(changeDimensionPacket); session.setDimension(javaDimension); - session.setDimensionType(session.getDimensions().get(javaDimension)); - ChunkUtils.loadDimension(session); + session.getChunkCache().setBedrockDimension(switch (javaDimension) { + case DimensionUtils.THE_END -> BedrockDimension.THE_END; + case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; + default -> BedrockDimension.OVERWORLD; + }); player.setPosition(pos); session.setSpawned(false); session.setLastChunkPosition(null); From 886d7e5b4b44e84a7cf91139ac9305b2180c8c88 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 12 Nov 2022 10:28:53 -0500 Subject: [PATCH 242/290] Fix crashes when joining a server in the Nether --- .../geyser/session/GeyserSession.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 1 + .../geysermc/geyser/util/DimensionUtils.java | 24 +++++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 67aedec15..5fd01f541 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1420,7 +1420,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1L); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension)); + startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension())); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); startGamePacket.setDifficulty(1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index ea0de7851..a0d418324 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -99,6 +99,7 @@ public class JavaLoginTranslator extends PacketTranslator BedrockDimension.THE_END; - case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; - default -> BedrockDimension.OVERWORLD; - }); + setBedrockDimension(session, javaDimension); player.setPosition(pos); session.setSpawned(false); session.setLastChunkPosition(null); @@ -137,6 +133,24 @@ public class DimensionUtils { } } + public static void setBedrockDimension(GeyserSession session, String javaDimension) { + session.getChunkCache().setBedrockDimension(switch (javaDimension) { + case DimensionUtils.THE_END -> BedrockDimension.THE_END; + case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; + default -> BedrockDimension.OVERWORLD; + }); + } + + public static int javaToBedrock(BedrockDimension dimension) { + if (dimension == BedrockDimension.THE_NETHER) { + return BEDROCK_NETHER_ID; + } else if (dimension == BedrockDimension.THE_END) { + return 2; + } else { + return 0; + } + } + /** * Map the Java edition dimension IDs to Bedrock edition * From 5ddb0ad90a7098ed5822e630b51717f6ebb9592d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 14 Nov 2022 15:12:46 -0500 Subject: [PATCH 243/290] Allow virtual inventories to be opened when player at world height commit c53bb38a47d1a48f0b5a72059e81c4354c2b8e90 Author: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon Nov 14 15:12:29 2022 -0500 Final touch commit f9ff9553eda7c80620a8e6f63e14f01adb39ac8b Merge: b57109ddf 886d7e5b4 Author: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon Nov 14 14:54:28 2022 -0500 Merge branch 'master' of https://github.com/GeyserMC/Geyser into pull/3281 commit b57109ddf7dabe77ca97f36de48d7266eaec08a1 Author: Kevin Ludwig Date: Mon Sep 12 12:23:36 2022 +0200 Revert use entities for single chest inventories commit fda66e83b90984505bdc3d87cf41e986dd10424b Author: Kevin Ludwig Date: Sat Sep 10 11:49:40 2022 +0200 Use entities for single chest inventories, check if a block for server-side opened inventories can be placed either above or below, otherwise, close the inventory (same logic as with inventory translator found) --- .../holder/BlockInventoryHolder.java | 28 +++++++++++++++---- .../inventory/holder/InventoryHolder.java | 2 +- .../AbstractBlockInventoryTranslator.java | 4 +-- .../inventory/InventoryTranslator.java | 2 +- .../inventory/LecternInventoryTranslator.java | 3 +- .../MerchantInventoryTranslator.java | 4 ++- .../inventory/PlayerInventoryTranslator.java | 3 +- .../chest/DoubleChestInventoryTranslator.java | 27 ++++++++++++++---- .../chest/SingleChestInventoryTranslator.java | 4 +-- .../AbstractHorseInventoryTranslator.java | 3 +- .../geysermc/geyser/util/InventoryUtils.java | 4 +-- 11 files changed, 61 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 379eb2566..eb15fa477 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -35,6 +35,7 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; @@ -49,6 +50,8 @@ import java.util.Set; * This class will attempt to use a real block first, if possible. */ public class BlockInventoryHolder extends InventoryHolder { + private static final int FAKE_BLOCK_DISTANCE = 1; + /** * The default Java block ID to translate as a fake block */ @@ -70,7 +73,7 @@ public class BlockInventoryHolder extends InventoryHolder { } @Override - public void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { + public boolean prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { // Check to see if there is an existing block we can use that the player just selected. // First, verify that the player's position has not changed, so we don't try to select a block wildly out of range. // (This could be a virtual inventory that the player is opening) @@ -83,13 +86,26 @@ public class BlockInventoryHolder extends InventoryHolder { inventory.setHolderPosition(session.getLastInteractionBlockPosition()); ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]); setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId); - return; + + return true; + } + } + + // Check if a fake block can be placed, either above the player or beneath. + BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); + int minY = dimension.minY(), maxY = minY + dimension.height(); + Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt(); + Vector3i position = flatPlayerPosition.add(Vector3i.UP); + if (position.getY() < minY) { + return false; + } + if (position.getY() >= maxY) { + position = flatPlayerPosition.sub(0, 4, 0); + if (position.getY() >= maxY) { + return false; } } - // Otherwise, time to conjure up a fake block! - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - position = position.add(Vector3i.UP); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(position); @@ -99,6 +115,8 @@ public class BlockInventoryHolder extends InventoryHolder { inventory.setHolderPosition(position); setCustomName(session, position, inventory, defaultJavaBlockState); + + return true; } /** diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java index fe54e1dc0..986df53db 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java @@ -30,7 +30,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; public abstract class InventoryHolder { - public abstract void prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); + public abstract boolean prepareInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); public abstract void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); public abstract void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java index c1fabcf0f..a24178161 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java @@ -65,8 +65,8 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - holder.prepareInventory(this, session, inventory); + public boolean prepareInventory(GeyserSession session, Inventory inventory) { + return holder.prepareInventory(this, session, inventory); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index 8c7ee1c80..e6cc010f5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -101,7 +101,7 @@ public abstract class InventoryTranslator { public final int size; - public abstract void prepareInventory(GeyserSession session, Inventory inventory); + public abstract boolean prepareInventory(GeyserSession session, Inventory inventory); public abstract void openInventory(GeyserSession session, Inventory inventory); public abstract void closeInventory(GeyserSession session, Inventory inventory); public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 7b2f861f5..59fe81751 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -55,7 +55,8 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { + public boolean prepareInventory(GeyserSession session, Inventory inventory) { + return true; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index 5e9c99ae9..857b96e55 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -94,7 +94,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { + public boolean prepareInventory(GeyserSession session, Inventory inventory) { MerchantContainer merchantInventory = (MerchantContainer) inventory; if (merchantInventory.getVillager() == null) { long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); @@ -117,6 +117,8 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { merchantInventory.setVillager(villager); } + + return true; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index ee7d6a7c6..8432b0253 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -514,7 +514,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { + public boolean prepareInventory(GeyserSession session, Inventory inventory) { + return true; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 0dd8553fd..5bf96fd39 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -35,11 +35,12 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.level.BedrockDimension; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.DoubleChestValue; -import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator; +import org.geysermc.geyser.registry.BlockRegistries; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { private final int defaultJavaBlockState; @@ -50,7 +51,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { + public boolean prepareInventory(GeyserSession session, Inventory inventory) { // See BlockInventoryHolder - same concept there except we're also dealing with a specific block state if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) { int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition()); @@ -76,11 +77,25 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { dataPacket.setData(tag.build()); dataPacket.setBlockPosition(session.getLastInteractionBlockPosition()); session.sendUpstreamPacket(dataPacket); - return; + + return true; + } + } + + // Check if a fake block can be placed, either above the player or beneath. + BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); + int minY = dimension.minY(), maxY = minY + dimension.height(); + Vector3i position = session.getPlayerEntity().getPosition().toInt().add(0, 5, 0); + if (position.getY() < minY) { + return false; + } + if (position.getY() >= maxY) { + position = session.getPlayerEntity().getPosition().toInt().sub(0, 5, 0); + if (position.getY() >= maxY) { + return false; } } - Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP); Vector3i pairPosition = position.add(Vector3i.UNIT_X); int bedrockBlockId = session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState); @@ -125,6 +140,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { session.sendUpstreamPacket(dataPacket); inventory.setHolderPosition(position); + + return true; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index 41e7bfb9f..ae914ed8c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -52,8 +52,8 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - holder.prepareInventory(this, session, inventory); + public boolean prepareInventory(GeyserSession session, Inventory inventory) { + return holder.prepareInventory(this, session, inventory); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java index 0ad6ba137..538133e0e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java @@ -40,7 +40,8 @@ public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTran } @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { + public boolean prepareInventory(GeyserSession session, Inventory inventory) { + return true; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index 56da67bec..ce88bc69c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -85,8 +85,7 @@ public class InventoryUtils { public static void displayInventory(GeyserSession session, Inventory inventory) { InventoryTranslator translator = session.getInventoryTranslator(); - if (translator != null) { - translator.prepareInventory(session, inventory); + if (translator != null && translator.prepareInventory(session, inventory)) { if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) { session.scheduleInEventLoop(() -> { Inventory openInv = session.getOpenInventory(); @@ -103,7 +102,6 @@ public class InventoryUtils { translator.updateInventory(session, inventory); } } else { - // Precaution - as of 1.16 every inventory should be translated so this shouldn't happen session.setOpenInventory(null); } } From 3338f5c707bd82dc54b55895276ef90801233e9f Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 15 Nov 2022 11:50:58 -0500 Subject: [PATCH 244/290] Remove duplicate inventory logic --- .../holder/BlockInventoryHolder.java | 21 +++-------- .../chest/DoubleChestInventoryTranslator.java | 19 +++------- .../geysermc/geyser/util/InventoryUtils.java | 36 ++++++++++++------- 3 files changed, 33 insertions(+), 43 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index eb15fa477..3e0892be4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.inventory.holder; -import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; @@ -35,11 +34,11 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.InventoryUtils; import java.util.Collections; import java.util.HashSet; @@ -50,8 +49,6 @@ import java.util.Set; * This class will attempt to use a real block first, if possible. */ public class BlockInventoryHolder extends InventoryHolder { - private static final int FAKE_BLOCK_DISTANCE = 1; - /** * The default Java block ID to translate as a fake block */ @@ -66,7 +63,7 @@ public class BlockInventoryHolder extends InventoryHolder { Set validBlocksTemp = new HashSet<>(validBlocks.length + 1); Collections.addAll(validBlocksTemp, validBlocks); validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); - this.validBlocks = ImmutableSet.copyOf(validBlocksTemp); + this.validBlocks = Set.copyOf(validBlocksTemp); } else { this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier)); } @@ -91,20 +88,10 @@ public class BlockInventoryHolder extends InventoryHolder { } } - // Check if a fake block can be placed, either above the player or beneath. - BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); - int minY = dimension.minY(), maxY = minY + dimension.height(); - Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt(); - Vector3i position = flatPlayerPosition.add(Vector3i.UP); - if (position.getY() < minY) { + Vector3i position = InventoryUtils.findAvailableWorldSpace(session); + if (position == null) { return false; } - if (position.getY() >= maxY) { - position = flatPlayerPosition.sub(0, 4, 0); - if (position.getY() >= maxY) { - return false; - } - } UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index 5bf96fd39..fa20e6dbb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -35,12 +35,12 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.level.BedrockDimension; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.DoubleChestValue; -import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator; +import org.geysermc.geyser.util.InventoryUtils; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { private final int defaultJavaBlockState; @@ -82,19 +82,10 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { } } - // Check if a fake block can be placed, either above the player or beneath. - BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); - int minY = dimension.minY(), maxY = minY + dimension.height(); - Vector3i position = session.getPlayerEntity().getPosition().toInt().add(0, 5, 0); - if (position.getY() < minY) { + Vector3i position = InventoryUtils.findAvailableWorldSpace(session); + if (position == null) { return false; } - if (position.getY() >= maxY) { - position = session.getPlayerEntity().getPosition().toInt().sub(0, 5, 0); - if (position.getY() >= maxY) { - return false; - } - } Vector3i pairPosition = position.add(Vector3i.UNIT_X); int bedrockBlockId = session.getBlockMappings().getBedrockBlockId(defaultJavaBlockState); diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index ce88bc69c..cb426963c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; @@ -46,6 +47,7 @@ import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -134,6 +136,28 @@ public class InventoryUtils { } } + /** + * Finds a usable block space in the world to place a fake inventory block, and returns the position. + */ + @Nullable + public static Vector3i findAvailableWorldSpace(GeyserSession session) { + // Check if a fake block can be placed, either above the player or beneath. + BedrockDimension dimension = session.getChunkCache().getBedrockDimension(); + int minY = dimension.minY(), maxY = minY + dimension.height(); + Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt(); + Vector3i position = flatPlayerPosition.add(Vector3i.UP); + if (position.getY() < minY) { + return null; + } + if (position.getY() >= maxY) { + position = flatPlayerPosition.sub(0, 4, 0); + if (position.getY() >= maxY) { + return null; + } + } + return position; + } + public static void updateCursor(GeyserSession session) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.UI); @@ -148,18 +172,6 @@ public class InventoryUtils { return item1.getJavaId() == item2.getJavaId() && Objects.equals(item1.getNbt(), item2.getNbt()); } - public static boolean canStack(ItemStack item1, ItemStack item2) { - if (item1 == null || item2 == null) - return false; - return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt()); - } - - public static boolean canStack(ItemData item1, ItemData item2) { - if (item1 == null || item2 == null) - return false; - return item1.equals(item2, false, true, true); - } - /** * Checks to see if an item stack represents air or has no count. */ From 37931e49968ca774fcc4cc21fb88db14072ae430 Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Fri, 18 Nov 2022 18:36:18 +0100 Subject: [PATCH 245/290] Fix potion recipes not working on pre-1.12 servers (#3408) --- .../java/org/geysermc/geyser/session/GeyserSession.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 5fd01f541..51648f8a2 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -629,6 +629,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { creativePacket.setContents(this.itemMappings.getCreativeItems()); upstream.sendPacket(creativePacket); + // Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand. + CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); + craftingDataPacket.setCleanRecipes(true); + craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get()); + upstream.sendPacket(craftingDataPacket); + PlayStatusPacket playStatusPacket = new PlayStatusPacket(); playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); From 7171ade0bd2da19fc70e3c36005371c50048ab2a Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Fri, 18 Nov 2022 11:04:22 -0800 Subject: [PATCH 246/290] Prevent double placement for custom block items (#3399) --- .../populator/CustomItemRegistryPopulator.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 94e04e972..0e40f9c43 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -124,6 +124,10 @@ public class CustomItemRegistryPopulator { computeArmorProperties(mapping.getArmorType(), mapping.getProtectionValue(), componentBuilder); } + if (mapping.getFirstBlockRuntimeId() != null) { + computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder); + } + computeRenderOffsets(false, customItemData, componentBuilder); componentBuilder.putCompound("item_properties", itemProperties.build()); @@ -260,6 +264,15 @@ public class CustomItemRegistryPopulator { } } + private static void computeBlockItemProperties(String blockItem, NbtMapBuilder componentBuilder) { + // carved pumpkin should be able to be worn and for that we would need to add wearable and armor with protection 0 here + // however this would have the side effect of preventing carved pumpkins from working as an attachable on the RP side outside the head slot + // it also causes the item to glitch when right clicked to "equip" so this should only be added here later if these issues can be overcome + + // all block items registered should be given this component to prevent double placement + componentBuilder.putCompound("minecraft:block_placer", NbtMap.builder().putString("block", blockItem).build()); + } + private static void computeRenderOffsets(boolean isHat, CustomItemData customItemData, NbtMapBuilder componentBuilder) { if (isHat) { componentBuilder.remove("minecraft:render_offsets"); From 759db72536e74eddd9b864a7ed6a6d6b7dda8e7b Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:13:59 -0500 Subject: [PATCH 247/290] Compiling for 1.19.3 --- .../type/living/monster/EndermanEntity.java | 15 ++- .../geyser/session/GeyserSession.java | 6 +- .../geysermc/geyser/text/ChatTypeEntry.java | 2 +- .../java/JavaPlayerChatTranslator.java | 2 +- .../JavaPlayerInfoRemoveTranslator.java | 65 +++++++++ .../player/JavaPlayerInfoTranslator.java | 125 ------------------ .../JavaPlayerInfoUpdateTranslator.java | 113 ++++++++++++++++ .../java/level/JavaExplodeTranslator.java | 7 +- gradle/libs.versions.toml | 4 +- 9 files changed, 201 insertions(+), 138 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoRemoveTranslator.java delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 03492d518..593cd9457 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -25,8 +25,9 @@ package org.geysermc.geyser.entity.type.living.monster; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.OptionalIntMetadataType; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -35,6 +36,7 @@ import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import java.util.OptionalInt; import java.util.UUID; public class EndermanEntity extends MonsterEntity { @@ -43,8 +45,15 @@ public class EndermanEntity extends MonsterEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - public void setCarriedBlock(IntEntityMetadata entityMetadata) { - dirtyMetadata.put(EntityData.CARRIED_BLOCK, session.getBlockMappings().getBedrockBlockId(entityMetadata.getPrimitiveValue())); + public void setCarriedBlock(EntityMetadata entityMetadata) { + int bedrockBlockId; + if (entityMetadata.getValue().isPresent()) { + bedrockBlockId = entityMetadata.getValue().getAsInt(); + } else { + bedrockBlockId = session.getBlockMappings().getBedrockAirId(); + } + + dirtyMetadata.put(EntityData.CARRIED_BLOCK, bedrockBlockId); } /** diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 51648f8a2..f4d7a174a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1360,18 +1360,20 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return clientData.getLanguageCode(); } + // TODO: 1.19.3 int offest and ack'd messages BitSet??? + /** * Sends a chat message to the Java server. */ public void sendChat(String message) { - sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false, Collections.emptyList(), null)); + sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); } /** * Sends a command to the Java server. */ public void sendCommand(String command) { - sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), false, Collections.emptyList(), null)); + sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); } public void setServerRenderDistance(int renderDistance) { diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java index c45de8f9f..af965ba8a 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.text; -import com.github.steveice10.mc.protocol.data.game.BuiltinChatType; +import com.github.steveice10.mc.protocol.data.game.chat.BuiltinChatType; import com.nukkitx.protocol.bedrock.packet.TextPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java index 143fa16a9..4c2d51cb8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java @@ -51,7 +51,7 @@ public class JavaPlayerChatTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundPlayerInfoRemovePacket packet) { + PlayerListPacket translate = new PlayerListPacket(); + translate.setAction(PlayerListPacket.Action.REMOVE); + + for (UUID id : packet.getProfileIds()) { + // As the player entity is no longer present, we can remove the entry + PlayerEntity entity = session.getEntityCache().removePlayerEntity(id); + if (entity != null) { + // Just remove the entity's player list status + // Don't despawn the entity - the Java server will also take care of that. + entity.setPlayerList(false); + } + if (entity == session.getPlayerEntity()) { + // If removing ourself we use our AuthData UUID + translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().uuid())); + } else { + translate.getEntries().add(new PlayerListPacket.Entry(id)); + } + } + + if (!translate.getEntries().isEmpty()) { + session.sendUpstreamPacket(translate); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoTranslator.java deleted file mode 100644 index 1cefb9731..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoTranslator.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.translator.protocol.java.entity.player; - -import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; -import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.skin.SkinManager; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -@Translator(packet = ClientboundPlayerInfoPacket.class) -public class JavaPlayerInfoTranslator extends PacketTranslator { - @Override - public void translate(GeyserSession session, ClientboundPlayerInfoPacket packet) { - if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) - return; - - PlayerListPacket translate = new PlayerListPacket(); - translate.setAction(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Action.ADD : PlayerListPacket.Action.REMOVE); - - for (PlayerListEntry entry : packet.getEntries()) { - switch (packet.getAction()) { - case ADD_PLAYER -> { - GameProfile profile = entry.getProfile(); - PlayerEntity playerEntity; - boolean self = profile.getId().equals(session.getPlayerEntity().getUuid()); - - if (self) { - // Entity is ourself - playerEntity = session.getPlayerEntity(); - } else { - playerEntity = session.getEntityCache().getPlayerEntity(profile.getId()); - } - - GameProfile.Property textures = profile.getProperty("textures"); - String texturesProperty = textures == null ? null : textures.getValue(); - - if (playerEntity == null) { - // It's a new player - playerEntity = new PlayerEntity( - session, - -1, - session.getEntityCache().getNextEntityId().incrementAndGet(), - profile.getId(), - Vector3f.ZERO, - Vector3f.ZERO, - 0, 0, 0, - profile.getName(), - texturesProperty - ); - - session.getEntityCache().addPlayerEntity(playerEntity); - } else { - playerEntity.setUsername(profile.getName()); - playerEntity.setTexturesProperty(texturesProperty); - } - - playerEntity.setPlayerList(true); - - // We'll send our own PlayerListEntry in requestAndHandleSkinAndCape - // But we need to send other player's entries so they show up in the player list - // without processing their skin information - that'll be processed when they spawn in - if (self) { - SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> - GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername())); - } else { - playerEntity.setValid(true); - PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity); - - translate.getEntries().add(playerListEntry); - } - } - case REMOVE_PLAYER -> { - // As the player entity is no longer present, we can remove the entry - PlayerEntity entity = session.getEntityCache().removePlayerEntity(entry.getProfile().getId()); - if (entity != null) { - // Just remove the entity's player list status - // Don't despawn the entity - the Java server will also take care of that. - entity.setPlayerList(false); - } - if (entity == session.getPlayerEntity()) { - // If removing ourself we use our AuthData UUID - translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().uuid())); - } else { - translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId())); - } - } - } - } - - if (!translate.getEntries().isEmpty()) { - session.sendUpstreamPacket(translate); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java new file mode 100644 index 000000000..24989c701 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.java.entity.player; + +import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; +import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.skin.SkinManager; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; + +@Translator(packet = ClientboundPlayerInfoUpdatePacket.class) +public class JavaPlayerInfoUpdateTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundPlayerInfoUpdatePacket packet) { + if (!packet.getActions().contains(PlayerListEntryAction.ADD_PLAYER)) { + return; + } + + PlayerListPacket translate = new PlayerListPacket(); + translate.setAction(PlayerListPacket.Action.ADD); + + for (PlayerListEntry entry : packet.getEntries()) { + for (PlayerListEntryAction action : packet.getActions()) { + if (action != PlayerListEntryAction.ADD_PLAYER) { + continue; + } + + GameProfile profile = entry.getProfile(); + PlayerEntity playerEntity; + boolean self = profile.getId().equals(session.getPlayerEntity().getUuid()); + + if (self) { + // Entity is ourself + playerEntity = session.getPlayerEntity(); + } else { + playerEntity = session.getEntityCache().getPlayerEntity(profile.getId()); + } + + GameProfile.Property textures = profile.getProperty("textures"); + String texturesProperty = textures == null ? null : textures.getValue(); + + if (playerEntity == null) { + // It's a new player + playerEntity = new PlayerEntity( + session, + -1, + session.getEntityCache().getNextEntityId().incrementAndGet(), + profile.getId(), + Vector3f.ZERO, + Vector3f.ZERO, + 0, 0, 0, + profile.getName(), + texturesProperty + ); + + session.getEntityCache().addPlayerEntity(playerEntity); + } else { + playerEntity.setUsername(profile.getName()); + playerEntity.setTexturesProperty(texturesProperty); + } + + playerEntity.setPlayerList(true); + + // We'll send our own PlayerListEntry in requestAndHandleSkinAndCape + // But we need to send other player's entries so they show up in the player list + // without processing their skin information - that'll be processed when they spawn in + if (self) { + SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> + GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername())); + } else { + playerEntity.setValid(true); + PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity); + + translate.getEntries().add(playerListEntry); + } + } + } + + if (!translate.getEntries().isEmpty()) { + session.sendUpstreamPacket(translate); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index 51c508e57..0e90831ff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -30,7 +30,6 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelEventGenericPacket; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; @@ -49,9 +48,9 @@ public class JavaExplodeTranslator extends PacketTranslator Date: Tue, 22 Nov 2022 18:58:34 -0500 Subject: [PATCH 248/290] Recipe fix thing --- .../geyser/registry/populator/RecipeRegistryPopulator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index 920ada5fb..6b6bfe9fe 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -82,8 +82,6 @@ public class RecipeRegistryPopulator { Collections.singletonList(CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), ++LAST_RECIPE_NET_ID))); craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPCLONING, Collections.singletonList(CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), ++LAST_RECIPE_NET_ID))); - craftingData.put(RecipeType.CRAFTING_SPECIAL_BANNERADDPATTERN, - Collections.singletonList(CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), ++LAST_RECIPE_NET_ID))); // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php From b35667d187bbfaff3841b7f18ec1ed085de74a0c Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 22 Nov 2022 19:02:01 -0500 Subject: [PATCH 249/290] Fix mistake on Enderman carried block updater --- .../geyser/entity/type/living/monster/EndermanEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 593cd9457..04b46997d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -48,7 +48,7 @@ public class EndermanEntity extends MonsterEntity { public void setCarriedBlock(EntityMetadata entityMetadata) { int bedrockBlockId; if (entityMetadata.getValue().isPresent()) { - bedrockBlockId = entityMetadata.getValue().getAsInt(); + bedrockBlockId = session.getBlockMappings().getBedrockBlockId(entityMetadata.getValue().getAsInt()); } else { bedrockBlockId = session.getBlockMappings().getBedrockAirId(); } From 70a8272bc24149395caae1dcc64a433b65728f3f Mon Sep 17 00:00:00 2001 From: Comstepr <32700815+Comstepr@users.noreply.github.com> Date: Thu, 24 Nov 2022 09:10:04 +0800 Subject: [PATCH 250/290] Bump jackson-databind to 2.14.0 (#3406) --- build-logic/build.gradle.kts | 4 ++-- gradle/libs.versions.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index c992a3ca9..e21806660 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -16,11 +16,11 @@ dependencies { // Within the gradle plugin classpath, there is a version conflict between loom and some other // plugin for databind. This fixes it: minimum 2.13.2 is required by loom. - implementation("com.fasterxml.jackson.core:jackson-databind:2.13.3") + implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0") } tasks.withType { kotlinOptions { jvmTarget = "16" } -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3724836d9..b3f3df9c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -jackson = "2.13.4" +jackson = "2.14.0" fastutil = "8.5.2" netty = "4.1.80.Final" guava = "29.0-jre" @@ -95,4 +95,4 @@ jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ] fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ] adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] log4j = [ "log4j-api", "log4j-core", "log4j-slf4j18-impl" ] -jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] \ No newline at end of file +jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] From 1a1837619c9b10f203efd5712f3ba51b607a5849 Mon Sep 17 00:00:00 2001 From: onebeastchris Date: Thu, 24 Nov 2022 03:33:55 +0100 Subject: [PATCH 251/290] Option to specify the "unusable inventory space" item (#3402) Adds an "unusable-space-block" setting in the config.yml to specify an item to indicate unavailable spaces in a bedrock inventory. If the item is invalid, a barrier block is used & an error gets printed --- .../geyser/configuration/GeyserConfiguration.java | 2 ++ .../configuration/GeyserJacksonConfiguration.java | 3 +++ .../org/geysermc/geyser/util/InventoryUtils.java | 14 +++++++++++++- core/src/main/resources/config.yml | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index 109ad3211..8a366baae 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -111,6 +111,8 @@ public interface GeyserConfiguration { boolean isNotifyOnNewBedrockUpdate(); + String getUnusableSpaceBlock(); + IMetricsInfo getMetrics(); int getPendingAuthenticationTimeout(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 73e208963..229895c3c 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -154,6 +154,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("notify-on-new-bedrock-update") private boolean notifyOnNewBedrockUpdate = true; + @JsonProperty("unusable-space-block") + private String unusableSpaceBlock = "minecraft:barrier"; + private MetricsInfo metrics = new MetricsInfo(); @JsonProperty("pending-authentication-timeout") diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index ce88bc69c..4b001901d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -38,6 +38,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; @@ -184,11 +185,22 @@ public class InventoryUtils { root.put("display", display.build()); return protocolVersion -> ItemData.builder() - .id(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().barrier().getBedrockId()) + .id(getUnusableSpaceBlockID(protocolVersion)) .count(1) .tag(root.build()).build(); } + private static int getUnusableSpaceBlockID(int protocolVersion) { + String unusableSpaceBlock = GeyserImpl.getInstance().getConfig().getUnusableSpaceBlock(); + ItemMapping unusableSpaceBlockID = Registries.ITEMS.forVersion(protocolVersion).getMapping(unusableSpaceBlock); + if (unusableSpaceBlockID != null) { + return unusableSpaceBlockID.getBedrockId(); + } else { + GeyserImpl.getInstance().getLogger().error("Invalid value" + unusableSpaceBlock + ". Resorting to barrier block."); + return Registries.ITEMS.forVersion(protocolVersion).getStoredItems().barrier().getBedrockId(); + } + } + /** * See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}. * diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index d5b9c755f..502441560 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -183,6 +183,10 @@ log-player-ip-addresses: true # auto-update. notify-on-new-bedrock-update: true +# Which item to use to mark unavailable slots in a Bedrock player inventory. Examples of this are the 2x2 crafting grid while in creative, +# or custom inventory menus with sizes different from the usual 3x9. A barrier block is the default item. +unusable-space-block: minecraft:barrier + # bStats is a stat tracker that is entirely anonymous and tracks only basic information # about Geyser, such as how many people are online, how many servers are using Geyser, # what OS is being used, etc. You can learn more about bStats here: https://bstats.org/. From f505f132162f6cac0ac6aa451f9c5b123829f822 Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Thu, 24 Nov 2022 21:19:55 +0100 Subject: [PATCH 252/290] Fix issues with sending multiple Bedrock resource packs (#3416) --- .../geyser/network/UpstreamPacketHandler.java | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index c2a91fd75..227f0ed5a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -46,9 +46,13 @@ import org.geysermc.geyser.util.MathUtils; import java.io.FileInputStream; import java.io.InputStream; +import java.util.ArrayDeque; +import java.util.Deque; public class UpstreamPacketHandler extends LoggingPacketHandler { + private Deque packsToSent = new ArrayDeque<>(); + public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) { super(geyser, session); } @@ -161,24 +165,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { break; case SEND_PACKS: - for(String id : packet.getPackIds()) { - ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket(); - String[] packID = id.split("_"); - ResourcePack pack = ResourcePack.PACKS.get(packID[0]); - ResourcePackManifest.Header header = pack.getManifest().getHeader(); - - data.setPackId(header.getUuid()); - int chunkCount = (int) Math.ceil((int) pack.getFile().length() / (double) ResourcePack.CHUNK_SIZE); - data.setChunkCount(chunkCount); - data.setCompressedPackSize(pack.getFile().length()); - data.setMaxChunkSize(ResourcePack.CHUNK_SIZE); - data.setHash(pack.getSha256()); - data.setPackVersion(packID[1]); - data.setPremium(false); - data.setType(ResourcePackType.RESOURCE); - - session.sendUpstreamPacket(data); - } + packsToSent.addAll(packet.getPackIds()); + sendPackDataInfo(packsToSent.pop()); break; case HAVE_ALL_PACKS: @@ -271,7 +259,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { data.setPackId(packet.getPackId()); int offset = packet.getChunkIndex() * ResourcePack.CHUNK_SIZE; - byte[] packData = new byte[(int) MathUtils.constrain(pack.getFile().length() - offset, 0, ResourcePack.CHUNK_SIZE)]; + long remainingSize = pack.getFile().length() - offset; + byte[] packData = new byte[(int) MathUtils.constrain(remainingSize, 0, ResourcePack.CHUNK_SIZE)]; try (InputStream inputStream = new FileInputStream(pack.getFile())) { inputStream.skip(offset); @@ -283,6 +272,31 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { data.setData(packData); session.sendUpstreamPacket(data); + + // Check if it is the last chunk and send next pack in queue when available. + if (remainingSize <= ResourcePack.CHUNK_SIZE && !packsToSent.isEmpty()) { + sendPackDataInfo(packsToSent.pop()); + } + return true; } + + private void sendPackDataInfo(String id) { + ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket(); + String[] packID = id.split("_"); + ResourcePack pack = ResourcePack.PACKS.get(packID[0]); + ResourcePackManifest.Header header = pack.getManifest().getHeader(); + + data.setPackId(header.getUuid()); + int chunkCount = (int) Math.ceil((int) pack.getFile().length() / (double) ResourcePack.CHUNK_SIZE); + data.setChunkCount(chunkCount); + data.setCompressedPackSize(pack.getFile().length()); + data.setMaxChunkSize(ResourcePack.CHUNK_SIZE); + data.setHash(pack.getSha256()); + data.setPackVersion(packID[1]); + data.setPremium(false); + data.setType(ResourcePackType.RESOURCE); + + session.sendUpstreamPacket(data); + } } From 09cce58746fee8a7c9b1889bed099aeb89389eb1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:35:00 -0500 Subject: [PATCH 253/290] use my mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 10baa9a45..72f927083 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 10baa9a45de074afa643e8477bd5a4e72ecfa563 +Subproject commit 72f927083d8e08f1f1c736d7d12095c7eee3bc68 From 7dc2ca35d615a43f4c6e37fd5bd3e01a6b969c63 Mon Sep 17 00:00:00 2001 From: Kevin Ludwig <32491319+valaphee@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:46:07 +0100 Subject: [PATCH 254/290] Fully strip formatting from chat and commands (#3417) --- .../geyser/inventory/AnvilContainer.java | 2 +- .../BedrockCommandRequestTranslator.java | 11 +++++----- .../bedrock/BedrockTextTranslator.java | 16 +------------- .../translator/text/MessageTranslator.java | 22 +++++++++++++++++++ .../chat/MessageTranslatorTest.java | 1 + 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 141f2b6f2..471aff8b2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -76,7 +76,7 @@ public class AnvilContainer extends Container { String originalName = ItemUtils.getCustomName(getInput().getNbt()); String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale()); - String plainNewName = MessageTranslator.convertToPlainText(rename, session.locale()); + String plainNewName = MessageTranslator.convertToPlainText(rename); if (!plainOriginalName.equals(plainNewName)) { // Strip out formatting since Java Edition does not allow it correctRename = plainNewName; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 3301f7b9f..24fc8396f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -29,6 +29,7 @@ import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -38,16 +39,14 @@ public class BedrockCommandRequestTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, TextPacket packet) { - String message = packet.getMessage(); - - // The order here is important - strip out illegal characters first, then check if it's blank - // (in case the message is blank after removing) - if (message.indexOf(ChatColor.ESCAPE) != -1) { - // Filter out all escape characters - Java doesn't let you type these - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (c != ChatColor.ESCAPE) { - builder.append(c); - } - } - message = builder.toString(); - } + String message = MessageTranslator.convertToPlainText(packet.getMessage()); if (message.isBlank()) { // Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either! diff --git a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java index 10b1bbc5a..1b267823a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java @@ -201,6 +201,28 @@ public class MessageTranslator { return GSON_SERIALIZER.serialize(component); } + + /** + * Convert legacy format message to plain text + * + * @param message Message to convert + * @return The plain text of the message + */ + public static String convertToPlainText(String message) { + char[] input = message.toCharArray(); + char[] output = new char[input.length]; + int outputSize = 0; + for (int i = 0, inputLength = input.length; i < inputLength; i++) { + char c = input[i]; + if (c == ChatColor.ESCAPE) { + i++; + } else { + output[outputSize++] = c; + } + } + return new String(output, 0, outputSize); + } + /** * Convert JSON and legacy format message to plain text * diff --git a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java index 6a280ea57..e83c6f73d 100644 --- a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java +++ b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java @@ -85,6 +85,7 @@ public class MessageTranslatorTest { @Test public void convertToPlainText() { Assert.assertEquals("JSON message is not handled properly", "Many colors here", MessageTranslator.convertToPlainText("{\"extra\":[{\"color\":\"red\",\"text\":\"M\"},{\"color\":\"gold\",\"text\":\"a\"},{\"color\":\"yellow\",\"text\":\"n\"},{\"color\":\"green\",\"text\":\"y \"},{\"color\":\"aqua\",\"text\":\"c\"},{\"color\":\"dark_purple\",\"text\":\"o\"},{\"color\":\"red\",\"text\":\"l\"},{\"color\":\"gold\",\"text\":\"o\"},{\"color\":\"yellow\",\"text\":\"r\"},{\"color\":\"green\",\"text\":\"s \"},{\"color\":\"aqua\",\"text\":\"h\"},{\"color\":\"dark_purple\",\"text\":\"e\"},{\"color\":\"red\",\"text\":\"r\"},{\"color\":\"gold\",\"text\":\"e\"}],\"text\":\"\"}", "en_US")); + Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e")); Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e", "en_US")); Assert.assertEquals("Legacy formatted message is not handled properly (Style)", "Obf Bold Strikethrough Underline Italic Reset", MessageTranslator.convertToPlainText("§kObf §lBold §mStrikethrough §nUnderline §oItalic §rReset", "en_US")); Assert.assertEquals("Valid lenient JSON is not handled properly", "Strange", MessageTranslator.convertToPlainText("§rStrange", "en_US")); From 8f968230485f90e3eaa5109344bfd8ac0529b101 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Mon, 28 Nov 2022 20:53:17 -0600 Subject: [PATCH 255/290] Add support for Bedrock 1.19.50 (560) --- README.md | 2 +- .../geysermc/geyser/entity/type/Entity.java | 14 +- .../type/player/SessionPlayerEntity.java | 4 +- .../geysermc/geyser/network/GameProtocol.java | 15 +- .../populator/BlockRegistryPopulator.java | 11 +- .../populator/ItemRegistryPopulator.java | 5 +- .../geyser/session/GeyserSession.java | 185 +- ...BedrockInventoryTransactionTranslator.java | 26 +- .../JavaPlayerCombatKillTranslator.java | 2 +- .../geysermc/geyser/util/DimensionUtils.java | 18 + .../bedrock/block_palette.1_19_0.nbt | Bin 46005 -> 0 bytes .../bedrock/block_palette.1_19_50.nbt | Bin 0 -> 74726 bytes .../bedrock/creative_items.1_19_0.json | 5437 ----------------- ...19_10.json => creative_items.1_19_50.json} | 1482 ++--- .../bedrock/runtime_item_states.1_19_0.json | 4530 -------------- ....json => runtime_item_states.1_19_50.json} | 168 +- gradle/libs.versions.toml | 4 +- 17 files changed, 1058 insertions(+), 10845 deletions(-) delete mode 100644 core/src/main/resources/bedrock/block_palette.1_19_0.nbt create mode 100644 core/src/main/resources/bedrock/block_palette.1_19_50.nbt delete mode 100644 core/src/main/resources/bedrock/creative_items.1_19_0.json rename core/src/main/resources/bedrock/{creative_items.1_19_10.json => creative_items.1_19_50.json} (83%) delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_0.json rename core/src/main/resources/bedrock/{runtime_item_states.1_19_10.json => runtime_item_states.1_19_50.json} (97%) diff --git a/README.md b/README.md index a28ba8eb0..f5051ed04 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.0 - 1.19.40 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.50 and Minecraft Java 1.19.1/1.19.2. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index c4046bcf3..dbbdba05a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -44,6 +44,8 @@ import lombok.Setter; import net.kyori.adventure.text.Component; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.EntityUtils; @@ -353,10 +355,14 @@ public class Entity { public void setFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire - setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); - setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); - // Swimming is ignored here and instead we rely on the pose - setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); + // As of 1.19.50, the client does not want the sprinting, sneaking or gliding set on itself + if (!GameProtocol.supports1_19_50(session) || !(this instanceof SessionPlayerEntity sessionPlayer) || sessionPlayer.getSession() != session) { + setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); + setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); + + // Swimming is ignored here and instead we rely on the pose + setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); + } setInvisible((xd & 0x20) == 0x20); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index 74b95b73c..be1eca2c3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -116,7 +116,9 @@ public class SessionPlayerEntity extends PlayerEntity { @Override public void setFlags(ByteEntityMetadata entityMetadata) { super.setFlags(entityMetadata); - session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING)); + + byte flags = entityMetadata.getPrimitiveValue(); + session.setSwimmingInWater((flags & 0x10) == 0x10 && (flags & 0x08) == 0x08); refreshSpeed = true; } diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 7bba6bb89..d10111fee 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -34,6 +34,7 @@ import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import com.nukkitx.protocol.bedrock.v545.Bedrock_v545; import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; import com.nukkitx.protocol.bedrock.v557.Bedrock_v557; +import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -48,7 +49,7 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v557.V557_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v560.V560_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -61,9 +62,6 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v527.V527_CODEC.toBuilder() - .minecraftVersion("1.19.0/1.19.2") - .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v534.V534_CODEC.toBuilder() .minecraftVersion("1.19.10/1.19.11") .build()); @@ -74,6 +72,7 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder() .minecraftVersion("1.19.30/1.19.31") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } @@ -93,14 +92,14 @@ public final class GameProtocol { /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ - public static boolean supports1_19_10(GeyserSession session) { - return session.getUpstream().getProtocolVersion() >= Bedrock_v534.V534_CODEC.getProtocolVersion(); - } - public static boolean supports1_19_30(GeyserSession session) { return session.getUpstream().getProtocolVersion() >= Bedrock_v554.V554_CODEC.getProtocolVersion(); } + public static boolean supports1_19_50(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v560.V560_CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index afc79082a..cbab03990 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; +import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -73,13 +74,9 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_19_0", Bedrock_v527.V527_CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> { - if (bedrockIdentifier.equals("minecraft:muddy_mangrove_roots")) { - statesBuilder.remove("pillar_axis"); - } - return null; - }) - .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper).build(); + .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper) + .put(ObjectIntPair.of("1_19_50", Bedrock_v560.V560_CODEC.getProtocolVersion()), emptyMapper) + .build(); for (Map.Entry, BiFunction> palette : blockMappers.entrySet()) { NbtList blocksTag; diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index f928361cc..4b218aa7d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -37,6 +37,7 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; import it.unimi.dsi.fastutil.ints.*; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; @@ -76,10 +77,8 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.V527_CODEC.getProtocolVersion(), - Collections.singletonMap("minecraft:trader_llama_spawn_egg", "minecraft:llama_spawn_egg"))); - paletteVersions.put("1_19_10", new PaletteVersion(Bedrock_v534.V534_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.V544_CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.V560_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 51648f8a2..0d4eee1dd 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -58,19 +58,55 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; -import com.github.steveice10.packetlib.event.session.*; +import com.github.steveice10.packetlib.event.session.ConnectedEvent; +import com.github.steveice10.packetlib.event.session.DisconnectedEvent; +import com.github.steveice10.packetlib.event.session.PacketErrorEvent; +import com.github.steveice10.packetlib.event.session.PacketSendingEvent; +import com.github.steveice10.packetlib.event.session.SessionAdapter; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpSession; import com.nukkitx.math.GenericMath; -import com.nukkitx.math.vector.*; +import com.nukkitx.math.vector.Vector2f; +import com.nukkitx.math.vector.Vector2i; +import com.nukkitx.math.vector.Vector3d; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockServerSession; -import com.nukkitx.protocol.bedrock.data.*; +import com.nukkitx.protocol.bedrock.data.Ability; +import com.nukkitx.protocol.bedrock.data.AbilityLayer; +import com.nukkitx.protocol.bedrock.data.AttributeData; +import com.nukkitx.protocol.bedrock.data.AuthoritativeMovementMode; +import com.nukkitx.protocol.bedrock.data.ChatRestrictionLevel; +import com.nukkitx.protocol.bedrock.data.GamePublishSetting; +import com.nukkitx.protocol.bedrock.data.GameRuleData; +import com.nukkitx.protocol.bedrock.data.GameType; +import com.nukkitx.protocol.bedrock.data.PlayerPermission; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.SyncedPlayerMovementSettings; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.packet.AvailableEntityIdentifiersPacket; +import com.nukkitx.protocol.bedrock.packet.BiomeDefinitionListPacket; +import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; +import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket; +import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; +import com.nukkitx.protocol.bedrock.packet.CreativeContentPacket; +import com.nukkitx.protocol.bedrock.packet.EmoteListPacket; +import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; +import com.nukkitx.protocol.bedrock.packet.ItemComponentPacket; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet; +import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerFogPacket; +import com.nukkitx.protocol.bedrock.packet.SetTimePacket; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import com.nukkitx.protocol.bedrock.packet.TextPacket; +import com.nukkitx.protocol.bedrock.packet.TransferPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateAbilitiesPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateAdventureSettingsPacket; +import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; import io.netty.channel.Channel; import io.netty.channel.EventLoop; import it.unimi.dsi.fastutil.bytes.ByteArrays; @@ -127,7 +163,20 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; -import org.geysermc.geyser.session.cache.*; +import org.geysermc.geyser.session.cache.AdvancementsCache; +import org.geysermc.geyser.session.cache.BookEditCache; +import org.geysermc.geyser.session.cache.ChunkCache; +import org.geysermc.geyser.session.cache.EntityCache; +import org.geysermc.geyser.session.cache.EntityEffectCache; +import org.geysermc.geyser.session.cache.FormCache; +import org.geysermc.geyser.session.cache.LodestoneCache; +import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.session.cache.PreferencesCache; +import org.geysermc.geyser.session.cache.SkullCache; +import org.geysermc.geyser.session.cache.TagCache; +import org.geysermc.geyser.session.cache.TeleportCache; +import org.geysermc.geyser.session.cache.WorldBorder; +import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -143,7 +192,14 @@ import java.net.ConnectException; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -1228,7 +1284,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.pose = Pose.SNEAKING; playerEntity.setBoundingBoxHeight(1.5f); } - playerEntity.setFlag(EntityFlag.SNEAKING, sneaking); + + // As of 1.19.50, the client does not want sneaking set on itself + if (!GameProtocol.supports1_19_50(this)) { + playerEntity.setFlag(EntityFlag.SNEAKING, sneaking); + } } public void setSwimming(boolean swimming) { @@ -1628,76 +1688,40 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { boolean spectator = gameMode == GameMode.SPECTATOR; boolean worldImmutable = gameMode == GameMode.ADVENTURE || spectator; - if (GameProtocol.supports1_19_10(this)) { - UpdateAdventureSettingsPacket adventureSettingsPacket = new UpdateAdventureSettingsPacket(); - adventureSettingsPacket.setNoMvP(false); - adventureSettingsPacket.setNoPvM(false); - adventureSettingsPacket.setImmutableWorld(worldImmutable); - adventureSettingsPacket.setShowNameTags(false); - adventureSettingsPacket.setAutoJump(true); - sendUpstreamPacket(adventureSettingsPacket); + UpdateAdventureSettingsPacket adventureSettingsPacket = new UpdateAdventureSettingsPacket(); + adventureSettingsPacket.setNoMvP(false); + adventureSettingsPacket.setNoPvM(false); + adventureSettingsPacket.setImmutableWorld(worldImmutable); + adventureSettingsPacket.setShowNameTags(false); + adventureSettingsPacket.setAutoJump(true); + sendUpstreamPacket(adventureSettingsPacket); - UpdateAbilitiesPacket updateAbilitiesPacket = new UpdateAbilitiesPacket(); - updateAbilitiesPacket.setUniqueEntityId(bedrockId); - updateAbilitiesPacket.setCommandPermission(commandPermission); - updateAbilitiesPacket.setPlayerPermission(playerPermission); + UpdateAbilitiesPacket updateAbilitiesPacket = new UpdateAbilitiesPacket(); + updateAbilitiesPacket.setUniqueEntityId(bedrockId); + updateAbilitiesPacket.setCommandPermission(commandPermission); + updateAbilitiesPacket.setPlayerPermission(playerPermission); - AbilityLayer abilityLayer = new AbilityLayer(); - Set abilities = abilityLayer.getAbilityValues(); - if (canFly || spectator) { - abilities.add(Ability.MAY_FLY); - } - - // Default stuff we have to fill in - abilities.add(Ability.BUILD); - abilities.add(Ability.MINE); - // Needed so you can drop items - abilities.add(Ability.DOORS_AND_SWITCHES); - if (gameMode == GameMode.CREATIVE) { - // Needed so the client doesn't attempt to take away items - abilities.add(Ability.INSTABUILD); - } - - if (commandPermission == CommandPermission.OPERATOR) { - // Fixes a bug? since 1.19.11 where the player can change their gamemode in Bedrock settings and - // a packet is not sent to the server. - // https://github.com/GeyserMC/Geyser/issues/3191 - abilities.add(Ability.OPERATOR_COMMANDS); - } - - if (flying || spectator) { - if (spectator && !flying) { - // We're "flying locked" in this gamemode - flying = true; - ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true); - sendDownstreamPacket(abilitiesPacket); - } - abilities.add(Ability.FLYING); - } - - if (spectator) { - abilities.add(Ability.NO_CLIP); - } - - abilityLayer.setLayerType(AbilityLayer.Type.BASE); - abilityLayer.setFlySpeed(flySpeed); - // https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10 - abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed); - Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES); - - updateAbilitiesPacket.getAbilityLayers().add(abilityLayer); - sendUpstreamPacket(updateAbilitiesPacket); - return; + AbilityLayer abilityLayer = new AbilityLayer(); + Set abilities = abilityLayer.getAbilityValues(); + if (canFly || spectator) { + abilities.add(Ability.MAY_FLY); } - AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); - adventureSettingsPacket.setUniqueEntityId(bedrockId); - adventureSettingsPacket.setCommandPermission(commandPermission); - adventureSettingsPacket.setPlayerPermission(playerPermission); + // Default stuff we have to fill in + abilities.add(Ability.BUILD); + abilities.add(Ability.MINE); + // Needed so you can drop items + abilities.add(Ability.DOORS_AND_SWITCHES); + if (gameMode == GameMode.CREATIVE) { + // Needed so the client doesn't attempt to take away items + abilities.add(Ability.INSTABUILD); + } - Set flags = adventureSettingsPacket.getSettings(); - if (canFly || spectator) { - flags.add(AdventureSetting.MAY_FLY); + if (commandPermission == CommandPermission.OPERATOR) { + // Fixes a bug? since 1.19.11 where the player can change their gamemode in Bedrock settings and + // a packet is not sent to the server. + // https://github.com/GeyserMC/Geyser/issues/3191 + abilities.add(Ability.OPERATOR_COMMANDS); } if (flying || spectator) { @@ -1707,20 +1731,21 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true); sendDownstreamPacket(abilitiesPacket); } - flags.add(AdventureSetting.FLYING); - } - - if (worldImmutable) { - flags.add(AdventureSetting.WORLD_IMMUTABLE); + abilities.add(Ability.FLYING); } if (spectator) { - flags.add(AdventureSetting.NO_CLIP); + abilities.add(Ability.NO_CLIP); } - flags.add(AdventureSetting.AUTO_JUMP); + abilityLayer.setLayerType(AbilityLayer.Type.BASE); + abilityLayer.setFlySpeed(flySpeed); + // https://github.com/GeyserMC/Geyser/issues/3139 as of 1.19.10 + abilityLayer.setWalkSpeed(walkSpeed == 0f ? 0.01f : walkSpeed); + Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES); - sendUpstreamPacket(adventureSettingsPacket); + updateAbilitiesPacket.getAbilityLayers().add(abilityLayer); + sendUpstreamPacket(updateAbilitiesPacket); } private int getRenderDistance() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 436f26cb9..6992dada4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -32,12 +32,21 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import com.nukkitx.math.vector.Vector3d; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.inventory.*; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.LegacySetItemSlotData; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; @@ -54,7 +63,6 @@ import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -63,7 +71,11 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.CooldownUtils; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InventoryUtils; import java.util.List; import java.util.concurrent.TimeUnit; @@ -464,10 +476,8 @@ public class BedrockInventoryTransactionTranslator extends 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 diff --git a/core/src/main/resources/bedrock/block_palette.1_19_50.nbt b/core/src/main/resources/bedrock/block_palette.1_19_50.nbt new file mode 100644 index 0000000000000000000000000000000000000000..8b53566c5c9b8439b71c1fd4de7052cfd6e86590 GIT binary patch literal 74726 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 Date: Mon, 28 Nov 2022 21:00:24 -0600 Subject: [PATCH 256/290] Actually drop 1.19.10 support & remove redundant check --- core/src/main/java/org/geysermc/geyser/entity/type/Entity.java | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index dbbdba05a..fff15a494 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -356,7 +356,7 @@ public class Entity { byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire // As of 1.19.50, the client does not want the sprinting, sneaking or gliding set on itself - if (!GameProtocol.supports1_19_50(session) || !(this instanceof SessionPlayerEntity sessionPlayer) || sessionPlayer.getSession() != session) { + if (!GameProtocol.supports1_19_50(session) || !(this instanceof SessionPlayerEntity)) { setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index d10111fee..7aa64f1f7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -62,9 +62,6 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v534.V534_CODEC.toBuilder() - .minecraftVersion("1.19.10/1.19.11") - .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") From 49d3254ea925ac550e33f30dd785bbbbe56eaacd Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Mon, 28 Nov 2022 21:29:55 -0600 Subject: [PATCH 257/290] Use new Protocol version --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a784c0853..01b7179f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.80.Final" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "2.9.14-20221129.013131-3" +protocol = "2.9.15-20221129.032348-1" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" mcprotocollib = "9f78bd5" From c7e79299b698e9d4e89f508ee70667921d47792b Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:34:09 -0500 Subject: [PATCH 258/290] Improve 1.19.50 flags (#3422) --- .../java/org/geysermc/geyser/entity/type/Entity.java | 11 ++++------- .../entity/type/player/SessionPlayerEntity.java | 4 +--- .../org/geysermc/geyser/session/GeyserSession.java | 6 +----- gradle/libs.versions.toml | 2 +- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index fff15a494..663dd3c33 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -355,14 +355,11 @@ public class Entity { public void setFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire - // As of 1.19.50, the client does not want the sprinting, sneaking or gliding set on itself - if (!GameProtocol.supports1_19_50(session) || !(this instanceof SessionPlayerEntity)) { - setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); - setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); + setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); + setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); - // Swimming is ignored here and instead we rely on the pose - setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); - } + // Swimming is ignored here and instead we rely on the pose + setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); setInvisible((xd & 0x20) == 0x20); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index be1eca2c3..74b95b73c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -116,9 +116,7 @@ public class SessionPlayerEntity extends PlayerEntity { @Override public void setFlags(ByteEntityMetadata entityMetadata) { super.setFlags(entityMetadata); - - byte flags = entityMetadata.getPrimitiveValue(); - session.setSwimmingInWater((flags & 0x10) == 0x10 && (flags & 0x08) == 0x08); + session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING)); refreshSpeed = true; } diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 0d4eee1dd..17a609fb7 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1284,11 +1284,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.pose = Pose.SNEAKING; playerEntity.setBoundingBoxHeight(1.5f); } - - // As of 1.19.50, the client does not want sneaking set on itself - if (!GameProtocol.supports1_19_50(this)) { - playerEntity.setFlag(EntityFlag.SNEAKING, sneaking); - } + playerEntity.setFlag(EntityFlag.SNEAKING, sneaking); } public void setSwimming(boolean swimming) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 01b7179f3..5218c3e8a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.80.Final" guava = "29.0-jre" gson = "2.3.1" # Provided by Spigot 1.8.8 websocket = "1.5.1" -protocol = "2.9.15-20221129.032348-1" +protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" mcprotocollib = "9f78bd5" From c6e417a6af869cb49ca92503d6163cdd439df2ef Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 29 Nov 2022 23:59:01 -0500 Subject: [PATCH 259/290] Possibly fix #3421 --- .../geysermc/geyser/network/GameProtocol.java | 2 -- .../geysermc/geyser/util/DimensionUtils.java | 25 ++++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 7aa64f1f7..e85dc689d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -28,8 +28,6 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; -import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import com.nukkitx.protocol.bedrock.v545.Bedrock_v545; import com.nukkitx.protocol.bedrock.v554.Bedrock_v554; diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index edcbeefa7..887f42a8e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -123,6 +123,19 @@ public class DimensionUtils { stopSoundPacket.setSoundName(""); session.sendUpstreamPacket(stopSoundPacket); + // Kind of silly but Bedrock 1.19.50 requires an acknowledgement after the + // initial chunks are sent, prior to the client acknowledgement + if (GameProtocol.supports1_19_50(session)) { + // Note: send this before chunks are sent. Fixed https://github.com/GeyserMC/Geyser/issues/3421 + PlayerActionPacket ackPacket = new PlayerActionPacket(); + ackPacket.setRuntimeEntityId(player.getGeyserId()); + ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS); + ackPacket.setBlockPosition(Vector3i.ZERO); + ackPacket.setResultPosition(Vector3i.ZERO); + ackPacket.setFace(0); + session.sendUpstreamPacket(ackPacket); + } + // TODO - fix this hack of a fix by sending the final dimension switching logic after sections have been sent. // The client wants sections sent to it before it can successfully respawn. ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); @@ -137,18 +150,6 @@ public class DimensionUtils { session.removeFog("minecraft:fog_hell"); } } - - // Kind of silly but Bedrock 1.19.50 requires an acknowledgement after the - // initial chunks are sent, prior to the client acknowledgement - if (GameProtocol.supports1_19_50(session)) { - PlayerActionPacket ackPacket = new PlayerActionPacket(); - ackPacket.setRuntimeEntityId(player.getGeyserId()); - ackPacket.setAction(PlayerActionType.DIMENSION_CHANGE_SUCCESS); - ackPacket.setBlockPosition(Vector3i.ZERO); - ackPacket.setResultPosition(Vector3i.ZERO); - ackPacket.setFace(0); - session.sendUpstreamPacket(ackPacket); - } } public static void setBedrockDimension(GeyserSession session, String javaDimension) { From 8c70ac48d509ee10963d6e8510555a2e662edbe9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 30 Nov 2022 12:09:21 -0500 Subject: [PATCH 260/290] Fix maps in 1.19.50 Fixes #3427 --- .../protocol/java/level/JavaMapItemDataTranslator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java index 4685cf115..3a2d1a050 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaMapItemDataTranslator.java @@ -51,6 +51,8 @@ public class JavaMapItemDataTranslator extends PacketTranslator Date: Wed, 30 Nov 2022 16:05:35 -0500 Subject: [PATCH 261/290] Fix anvil usage in 1.19.50 --- .../translator/inventory/AnvilInventoryTranslator.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index 956fdeae0..52e542b7b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -59,10 +59,12 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { CraftRecipeOptionalStackRequestActionData data = (CraftRecipeOptionalStackRequestActionData) request.getActions()[0]; AnvilContainer container = (AnvilContainer) inventory; - // Required as of 1.18.30 - FilterTextPackets no longer appear to be sent - String name = request.getFilterStrings()[data.getFilteredStringIndex()]; - if (!Objects.equals(name, container.getNewName())) { - container.checkForRename(session, name); + if (request.getFilterStrings().length != 0) { + // Required as of 1.18.30 - FilterTextPackets no longer appear to be sent + String name = request.getFilterStrings()[data.getFilteredStringIndex()]; + if (!Objects.equals(name, container.getNewName())) { // TODO is this still necessary after pre-1.19.50 support is dropped? + container.checkForRename(session, name); + } } return super.translateRequest(session, inventory, request); From 1616b7740c252e147aa0ee96d68073d9fb34d438 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 1 Dec 2022 22:05:12 -0500 Subject: [PATCH 262/290] Bump mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 72f927083..19094e360 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 72f927083d8e08f1f1c736d7d12095c7eee3bc68 +Subproject commit 19094e36080d78212534f5f0d073fb5d3f68a89f From 58eede37c0ef2dac2b2c1c1a8671993dced9e6c5 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Fri, 2 Dec 2022 00:28:24 -0500 Subject: [PATCH 263/290] Drop anything below 1.19.50 --- .../geysermc/geyser/network/GameProtocol.java | 18 - .../populator/BlockRegistryPopulator.java | 3 - .../populator/ItemRegistryPopulator.java | 1 - .../BedrockRequestAbilityTranslator.java | 5 - .../geysermc/geyser/util/DimensionUtils.java | 18 +- .../bedrock/block_palette.1_19_20.nbt | Bin 55132 -> 0 bytes .../bedrock/creative_items.1_19_20.json | 5440 ----------------- .../bedrock/runtime_item_states.1_19_20.json | 4530 -------------- 8 files changed, 8 insertions(+), 10007 deletions(-) delete mode 100644 core/src/main/resources/bedrock/block_palette.1_19_20.nbt delete mode 100644 core/src/main/resources/bedrock/creative_items.1_19_20.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_20.json diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index e85dc689d..56159cfa8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -60,14 +60,6 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() - .minecraftVersion("1.19.21/1.19.22") - .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder() - .minecraftVersion("1.19.30/1.19.31") - .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } @@ -85,16 +77,6 @@ public final class GameProtocol { return null; } - /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ - - public static boolean supports1_19_30(GeyserSession session) { - return session.getUpstream().getProtocolVersion() >= Bedrock_v554.V554_CODEC.getProtocolVersion(); - } - - public static boolean supports1_19_50(GeyserSession session) { - return session.getUpstream().getProtocolVersion() >= Bedrock_v560.V560_CODEC.getProtocolVersion(); - } - /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index cbab03990..72116f548 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -29,8 +29,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; -import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; -import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -74,7 +72,6 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_19_50", Bedrock_v560.V560_CODEC.getProtocolVersion()), emptyMapper) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 4b218aa7d..645cf17ba 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -77,7 +77,6 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.V544_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.V560_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index fe8150d40..44953dfda 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -43,11 +43,6 @@ public class BedrockRequestAbilityTranslator extends PacketTranslatorX5GfPypkF`Ueo`Ex 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

    N!K?VWkIdC++V5CX^Dc;QTi}}9T=lerttP4d#b zb@t-=s{f05Iog>R1Xnsx(kBjuLM1(5y> z0`qrk9IcJ3+X^bauWCFyv*Q|9W3$obUsIWO6GmRVc&~n)wYRmd-o(d};}KuUSvr_< zo?aev3X z@?O();jB+SQW0T>*lBV|#ERayqI6_69C>_wlrJ2B*~T_zyVA)LGk_H(QOpU&q^aPc zgIaaCmZOZhK#J7-|J%$y!aAdFvA{53{F3{;m8ORSjLa;Yd0HZz1AiZcz$hmDM`Awa zn{-Jc@GLf5N>k!DrZJRc<1Di;v;f9x^n#gwRmlZFpeT_!p?pUzZBF&mka*oEPSx^3 z%4?=6**e=DBe_)h1LL%53-I%rtiTCBzA~3~2^a{$*?Ucsrhl{dEK;Yra)wkk6D;f` zTGJY90D-s%PIKUCK4_XQuZ!y-86EpCGadf7nMeO+rrdvH=H-8HrUaJBX=-j)FB5`v zQIKt9Qv^8%>R&&^`QnSxu&Fp5}1Li)>l8YTv9@r0ZJG;P5AP^?cZ9k;c1oTm@6?}pJ zIzgZEZyyB>sSSb4mB%**{(%8@LZt)k{ASHq_V=ML1%3ZzX666fOlaPgjik=}JWRvd z?+W4I@6-2dtjAl;)4`RdKUK2&n$d0piAM?yg}^}O7o^ZzRG4s>o2^<>lpu37+`n>F zuqyr-85+24$wO9Q)v)eIJ?^yZpk^agqM~c~^5}C*Mt3)pwabX8U4Nd__3uP7Z->8O zKwPFCId^Pi0`xyHR#^k9M&`)F7Hs@kBQ5%K94Lx^#YN~G4y%nvc$ur@K>|$EG zAKNdmu)?UQPP2YS zU=&B@Ra9zNLe2ROO+n^5G1=p$??b{bYTsXUWu8g(qoWFqbDVo8GMsqN@FsYKVTl z8lK9|?b-#)Zwz9VH%lp}R{E-1_D8c(moRQtfWn;P2kME5d;EbqxtsOQ1YUdN?gTlp vX!0f2XX*s~rfjqL4L=}#m+!XCdF;?V!=^KE4f37S^XE`*=^ZZ(bcp{2Ge*tJ diff --git a/core/src/main/resources/bedrock/creative_items.1_19_20.json b/core/src/main/resources/bedrock/creative_items.1_19_20.json deleted file mode 100644 index 98d9e007a..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_19_20.json +++ /dev/null @@ -1,5440 +0,0 @@ -{ - "items" : [ - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6073 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6074 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6075 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6076 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6077 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 6078 - }, - { - "id" : "minecraft:mangrove_planks", - "blockRuntimeId" : 949 - }, - { - "id" : "minecraft:crimson_planks", - "blockRuntimeId" : 4852 - }, - { - "id" : "minecraft:warped_planks", - "blockRuntimeId" : 922 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1184 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1185 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1186 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1187 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1188 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1189 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1196 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1191 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1192 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1190 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1193 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1197 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1194 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1195 - }, - { - "id" : "minecraft:blackstone_wall", - "blockRuntimeId" : 3932 - }, - { - "id" : "minecraft:polished_blackstone_wall", - "blockRuntimeId" : 6726 - }, - { - "id" : "minecraft:polished_blackstone_brick_wall", - "blockRuntimeId" : 973 - }, - { - "id" : "minecraft:cobbled_deepslate_wall", - "blockRuntimeId" : 8084 - }, - { - "id" : "minecraft:deepslate_tile_wall", - "blockRuntimeId" : 5073 - }, - { - "id" : "minecraft:polished_deepslate_wall", - "blockRuntimeId" : 7819 - }, - { - "id" : "minecraft:deepslate_brick_wall", - "blockRuntimeId" : 431 - }, - { - "id" : "minecraft:mud_brick_wall", - "blockRuntimeId" : 732 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7366 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7367 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7368 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7369 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7370 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 7371 - }, - { - "id" : "minecraft:mangrove_fence", - "blockRuntimeId" : 6635 - }, - { - "id" : "minecraft:nether_brick_fence", - "blockRuntimeId" : 4292 - }, - { - "id" : "minecraft:crimson_fence", - "blockRuntimeId" : 7998 - }, - { - "id" : "minecraft:warped_fence", - "blockRuntimeId" : 5855 - }, - { - "id" : "minecraft:fence_gate", - "blockRuntimeId" : 76 - }, - { - "id" : "minecraft:spruce_fence_gate", - "blockRuntimeId" : 6586 - }, - { - "id" : "minecraft:birch_fence_gate", - "blockRuntimeId" : 3779 - }, - { - "id" : "minecraft:jungle_fence_gate", - "blockRuntimeId" : 5367 - }, - { - "id" : "minecraft:acacia_fence_gate", - "blockRuntimeId" : 7588 - }, - { - "id" : "minecraft:dark_oak_fence_gate", - "blockRuntimeId" : 4175 - }, - { - "id" : "minecraft:mangrove_fence_gate", - "blockRuntimeId" : 4627 - }, - { - "id" : "minecraft:crimson_fence_gate", - "blockRuntimeId" : 4663 - }, - { - "id" : "minecraft:warped_fence_gate", - "blockRuntimeId" : 5401 - }, - { - "id" : "minecraft:normal_stone_stairs", - "blockRuntimeId" : 635 - }, - { - "id" : "minecraft:stone_stairs", - "blockRuntimeId" : 3710 - }, - { - "id" : "minecraft:mossy_cobblestone_stairs", - "blockRuntimeId" : 4094 - }, - { - "id" : "minecraft:oak_stairs", - "blockRuntimeId" : 273 - }, - { - "id" : "minecraft:spruce_stairs", - "blockRuntimeId" : 128 - }, - { - "id" : "minecraft:birch_stairs", - "blockRuntimeId" : 7005 - }, - { - "id" : "minecraft:jungle_stairs", - "blockRuntimeId" : 6969 - }, - { - "id" : "minecraft:acacia_stairs", - "blockRuntimeId" : 6202 - }, - { - "id" : "minecraft:dark_oak_stairs", - "blockRuntimeId" : 5065 - }, - { - "id" : "minecraft:mangrove_stairs", - "blockRuntimeId" : 4597 - }, - { - "id" : "minecraft:stone_brick_stairs", - "blockRuntimeId" : 933 - }, - { - "id" : "minecraft:mossy_stone_brick_stairs", - "blockRuntimeId" : 5885 - }, - { - "id" : "minecraft:sandstone_stairs", - "blockRuntimeId" : 3589 - }, - { - "id" : "minecraft:smooth_sandstone_stairs", - "blockRuntimeId" : 3629 - }, - { - "id" : "minecraft:red_sandstone_stairs", - "blockRuntimeId" : 5352 - }, - { - "id" : "minecraft:smooth_red_sandstone_stairs", - "blockRuntimeId" : 5548 - }, - { - "id" : "minecraft:granite_stairs", - "blockRuntimeId" : 3539 - }, - { - "id" : "minecraft:polished_granite_stairs", - "blockRuntimeId" : 4152 - }, - { - "id" : "minecraft:diorite_stairs", - "blockRuntimeId" : 4393 - }, - { - "id" : "minecraft:polished_diorite_stairs", - "blockRuntimeId" : 6716 - }, - { - "id" : "minecraft:andesite_stairs", - "blockRuntimeId" : 5310 - }, - { - "id" : "minecraft:polished_andesite_stairs", - "blockRuntimeId" : 7030 - }, - { - "id" : "minecraft:brick_stairs", - "blockRuntimeId" : 6532 - }, - { - "id" : "minecraft:nether_brick_stairs", - "blockRuntimeId" : 106 - }, - { - "id" : "minecraft:red_nether_brick_stairs", - "blockRuntimeId" : 6604 - }, - { - "id" : "minecraft:end_brick_stairs", - "blockRuntimeId" : 6384 - }, - { - "id" : "minecraft:quartz_stairs", - "blockRuntimeId" : 4769 - }, - { - "id" : "minecraft:smooth_quartz_stairs", - "blockRuntimeId" : 7702 - }, - { - "id" : "minecraft:purpur_stairs", - "blockRuntimeId" : 7757 - }, - { - "id" : "minecraft:prismarine_stairs", - "blockRuntimeId" : 7265 - }, - { - "id" : "minecraft:dark_prismarine_stairs", - "blockRuntimeId" : 7432 - }, - { - "id" : "minecraft:prismarine_bricks_stairs", - "blockRuntimeId" : 206 - }, - { - "id" : "minecraft:crimson_stairs", - "blockRuntimeId" : 6282 - }, - { - "id" : "minecraft:warped_stairs", - "blockRuntimeId" : 3720 - }, - { - "id" : "minecraft:blackstone_stairs", - "blockRuntimeId" : 7021 - }, - { - "id" : "minecraft:polished_blackstone_stairs", - "blockRuntimeId" : 4299 - }, - { - "id" : "minecraft:polished_blackstone_brick_stairs", - "blockRuntimeId" : 4479 - }, - { - "id" : "minecraft:cut_copper_stairs", - "blockRuntimeId" : 4606 - }, - { - "id" : "minecraft:exposed_cut_copper_stairs", - "blockRuntimeId" : 4589 - }, - { - "id" : "minecraft:weathered_cut_copper_stairs", - "blockRuntimeId" : 4307 - }, - { - "id" : "minecraft:oxidized_cut_copper_stairs", - "blockRuntimeId" : 353 - }, - { - "id" : "minecraft:waxed_cut_copper_stairs", - "blockRuntimeId" : 395 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_stairs", - "blockRuntimeId" : 3904 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_stairs", - "blockRuntimeId" : 6169 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_stairs", - "blockRuntimeId" : 5842 - }, - { - "id" : "minecraft:cobbled_deepslate_stairs", - "blockRuntimeId" : 147 - }, - { - "id" : "minecraft:deepslate_tile_stairs", - "blockRuntimeId" : 4655 - }, - { - "id" : "minecraft:polished_deepslate_stairs", - "blockRuntimeId" : 294 - }, - { - "id" : "minecraft:deepslate_brick_stairs", - "blockRuntimeId" : 7424 - }, - { - "id" : "minecraft:mud_brick_stairs", - "blockRuntimeId" : 5524 - }, - { - "id" : "minecraft:wooden_door" - }, - { - "id" : "minecraft:spruce_door" - }, - { - "id" : "minecraft:birch_door" - }, - { - "id" : "minecraft:jungle_door" - }, - { - "id" : "minecraft:acacia_door" - }, - { - "id" : "minecraft:dark_oak_door" - }, - { - "id" : "minecraft:mangrove_door" - }, - { - "id" : "minecraft:iron_door" - }, - { - "id" : "minecraft:crimson_door" - }, - { - "id" : "minecraft:warped_door" - }, - { - "id" : "minecraft:trapdoor", - "blockRuntimeId" : 229 - }, - { - "id" : "minecraft:spruce_trapdoor", - "blockRuntimeId" : 6554 - }, - { - "id" : "minecraft:birch_trapdoor", - "blockRuntimeId" : 6652 - }, - { - "id" : "minecraft:jungle_trapdoor", - "blockRuntimeId" : 5383 - }, - { - "id" : "minecraft:acacia_trapdoor", - "blockRuntimeId" : 5591 - }, - { - "id" : "minecraft:dark_oak_trapdoor", - "blockRuntimeId" : 7504 - }, - { - "id" : "minecraft:mangrove_trapdoor", - "blockRuntimeId" : 4487 - }, - { - "id" : "minecraft:iron_trapdoor", - "blockRuntimeId" : 321 - }, - { - "id" : "minecraft:crimson_trapdoor", - "blockRuntimeId" : 4335 - }, - { - "id" : "minecraft:warped_trapdoor", - "blockRuntimeId" : 4735 - }, - { - "id" : "minecraft:iron_bars", - "blockRuntimeId" : 4803 - }, - { - "id" : "minecraft:glass", - "blockRuntimeId" : 6166 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1135 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1143 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1142 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1150 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1147 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1149 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1136 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1139 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1140 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1148 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1144 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1138 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1146 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1145 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1137 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 1141 - }, - { - "id" : "minecraft:tinted_glass", - "blockRuntimeId" : 5977 - }, - { - "id" : "minecraft:glass_pane", - "blockRuntimeId" : 5235 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4854 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4862 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4861 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4869 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4866 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4868 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4855 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4858 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4859 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4867 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4863 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4857 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4865 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4864 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4856 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 4860 - }, - { - "id" : "minecraft:ladder", - "blockRuntimeId" : 8264 - }, - { - "id" : "minecraft:scaffolding", - "blockRuntimeId" : 3573 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4272 - }, - { - "id" : "minecraft:stone_block_slab4", - "blockRuntimeId" : 5824 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4275 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5795 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5272 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5273 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5274 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5275 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5276 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 5277 - }, - { - "id" : "minecraft:mangrove_slab", - "blockRuntimeId" : 1151 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4277 - }, - { - "id" : "minecraft:stone_block_slab4", - "blockRuntimeId" : 5822 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4273 - }, - { - "id" : "minecraft:stone_block_slab4", - "blockRuntimeId" : 5825 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5796 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5790 - }, - { - "id" : "minecraft:stone_block_slab4", - "blockRuntimeId" : 5826 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5807 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5812 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5813 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5810 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5811 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5809 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5808 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4276 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4279 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5797 - }, - { - "id" : "minecraft:stone_block_slab3", - "blockRuntimeId" : 5806 - }, - { - "id" : "minecraft:stone_block_slab", - "blockRuntimeId" : 4278 - }, - { - "id" : "minecraft:stone_block_slab4", - "blockRuntimeId" : 5823 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5791 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5792 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5793 - }, - { - "id" : "minecraft:stone_block_slab2", - "blockRuntimeId" : 5794 - }, - { - "id" : "minecraft:crimson_slab", - "blockRuntimeId" : 5902 - }, - { - "id" : "minecraft:warped_slab", - "blockRuntimeId" : 6486 - }, - { - "id" : "minecraft:blackstone_slab", - "blockRuntimeId" : 912 - }, - { - "id" : "minecraft:polished_blackstone_slab", - "blockRuntimeId" : 6020 - }, - { - "id" : "minecraft:polished_blackstone_brick_slab", - "blockRuntimeId" : 4194 - }, - { - "id" : "minecraft:cut_copper_slab", - "blockRuntimeId" : 5237 - }, - { - "id" : "minecraft:exposed_cut_copper_slab", - "blockRuntimeId" : 6602 - }, - { - "id" : "minecraft:weathered_cut_copper_slab", - "blockRuntimeId" : 6055 - }, - { - "id" : "minecraft:oxidized_cut_copper_slab", - "blockRuntimeId" : 5284 - }, - { - "id" : "minecraft:waxed_cut_copper_slab", - "blockRuntimeId" : 7817 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_slab", - "blockRuntimeId" : 249 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_slab", - "blockRuntimeId" : 6547 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_slab", - "blockRuntimeId" : 710 - }, - { - "id" : "minecraft:cobbled_deepslate_slab", - "blockRuntimeId" : 7312 - }, - { - "id" : "minecraft:polished_deepslate_slab", - "blockRuntimeId" : 288 - }, - { - "id" : "minecraft:deepslate_tile_slab", - "blockRuntimeId" : 4293 - }, - { - "id" : "minecraft:deepslate_brick_slab", - "blockRuntimeId" : 3718 - }, - { - "id" : "minecraft:mud_brick_slab", - "blockRuntimeId" : 3912 - }, - { - "id" : "minecraft:brick_block", - "blockRuntimeId" : 4767 - }, - { - "id" : "minecraft:chiseled_nether_bricks", - "blockRuntimeId" : 7251 - }, - { - "id" : "minecraft:cracked_nether_bricks", - "blockRuntimeId" : 4554 - }, - { - "id" : "minecraft:quartz_bricks", - "blockRuntimeId" : 6353 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 6549 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 6550 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 6551 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 6552 - }, - { - "id" : "minecraft:end_bricks", - "blockRuntimeId" : 281 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6089 - }, - { - "id" : "minecraft:polished_blackstone_bricks", - "blockRuntimeId" : 4682 - }, - { - "id" : "minecraft:cracked_polished_blackstone_bricks", - "blockRuntimeId" : 7216 - }, - { - "id" : "minecraft:gilded_blackstone", - "blockRuntimeId" : 4588 - }, - { - "id" : "minecraft:chiseled_polished_blackstone", - "blockRuntimeId" : 5064 - }, - { - "id" : "minecraft:deepslate_tiles", - "blockRuntimeId" : 4583 - }, - { - "id" : "minecraft:cracked_deepslate_tiles", - "blockRuntimeId" : 4162 - }, - { - "id" : "minecraft:deepslate_bricks", - "blockRuntimeId" : 5466 - }, - { - "id" : "minecraft:cracked_deepslate_bricks", - "blockRuntimeId" : 5366 - }, - { - "id" : "minecraft:chiseled_deepslate", - "blockRuntimeId" : 5236 - }, - { - "id" : "minecraft:cobblestone", - "blockRuntimeId" : 3617 - }, - { - "id" : "minecraft:mossy_cobblestone", - "blockRuntimeId" : 252 - }, - { - "id" : "minecraft:cobbled_deepslate", - "blockRuntimeId" : 6672 - }, - { - "id" : "minecraft:smooth_stone", - "blockRuntimeId" : 4584 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 3655 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 3656 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 3657 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 3658 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6582 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6583 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6584 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6585 - }, - { - "id" : "minecraft:coal_block", - "blockRuntimeId" : 5400 - }, - { - "id" : "minecraft:dried_kelp_block", - "blockRuntimeId" : 7981 - }, - { - "id" : "minecraft:gold_block", - "blockRuntimeId" : 291 - }, - { - "id" : "minecraft:iron_block", - "blockRuntimeId" : 8263 - }, - { - "id" : "minecraft:copper_block", - "blockRuntimeId" : 4653 - }, - { - "id" : "minecraft:exposed_copper", - "blockRuntimeId" : 595 - }, - { - "id" : "minecraft:weathered_copper", - "blockRuntimeId" : 8248 - }, - { - "id" : "minecraft:oxidized_copper", - "blockRuntimeId" : 3555 - }, - { - "id" : "minecraft:waxed_copper", - "blockRuntimeId" : 7736 - }, - { - "id" : "minecraft:waxed_exposed_copper", - "blockRuntimeId" : 696 - }, - { - "id" : "minecraft:waxed_weathered_copper", - "blockRuntimeId" : 709 - }, - { - "id" : "minecraft:waxed_oxidized_copper", - "blockRuntimeId" : 7544 - }, - { - "id" : "minecraft:cut_copper", - "blockRuntimeId" : 4691 - }, - { - "id" : "minecraft:exposed_cut_copper", - "blockRuntimeId" : 6168 - }, - { - "id" : "minecraft:weathered_cut_copper", - "blockRuntimeId" : 7199 - }, - { - "id" : "minecraft:oxidized_cut_copper", - "blockRuntimeId" : 5480 - }, - { - "id" : "minecraft:waxed_cut_copper", - "blockRuntimeId" : 7295 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper", - "blockRuntimeId" : 3811 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper", - "blockRuntimeId" : 4853 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper", - "blockRuntimeId" : 214 - }, - { - "id" : "minecraft:emerald_block", - "blockRuntimeId" : 1161 - }, - { - "id" : "minecraft:diamond_block", - "blockRuntimeId" : 272 - }, - { - "id" : "minecraft:lapis_block", - "blockRuntimeId" : 4288 - }, - { - "id" : "minecraft:raw_iron_block", - "blockRuntimeId" : 8262 - }, - { - "id" : "minecraft:raw_copper_block", - "blockRuntimeId" : 5271 - }, - { - "id" : "minecraft:raw_gold_block", - "blockRuntimeId" : 363 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 3698 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 3700 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 3699 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 3701 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6087 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6088 - }, - { - "id" : "minecraft:slime", - "blockRuntimeId" : 4235 - }, - { - "id" : "minecraft:honey_block", - "blockRuntimeId" : 894 - }, - { - "id" : "minecraft:honeycomb_block", - "blockRuntimeId" : 4478 - }, - { - "id" : "minecraft:hay_block", - "blockRuntimeId" : 697 - }, - { - "id" : "minecraft:bone_block", - "blockRuntimeId" : 4236 - }, - { - "id" : "minecraft:nether_brick", - "blockRuntimeId" : 7274 - }, - { - "id" : "minecraft:red_nether_brick", - "blockRuntimeId" : 146 - }, - { - "id" : "minecraft:netherite_block", - "blockRuntimeId" : 3777 - }, - { - "id" : "minecraft:lodestone", - "blockRuntimeId" : 8261 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3460 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3468 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3467 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3475 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3472 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3474 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3461 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3464 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3465 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3473 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3469 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3463 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3471 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3470 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3462 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 3466 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 951 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 959 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 958 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 966 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 963 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 965 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 952 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 955 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 956 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 964 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 960 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 954 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 962 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 961 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 953 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 957 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6266 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6274 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6273 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6281 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6278 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6280 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6267 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6270 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6271 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6279 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6275 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6269 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6277 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6276 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6268 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 6272 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 662 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 670 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 669 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 677 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 674 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 676 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 663 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 666 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 667 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 675 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 671 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 665 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 673 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 672 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 664 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 668 - }, - { - "id" : "minecraft:clay", - "blockRuntimeId" : 7126 - }, - { - "id" : "minecraft:hardened_clay", - "blockRuntimeId" : 643 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6178 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6186 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6185 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6193 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6190 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6192 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6179 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6182 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6183 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6191 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6187 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6181 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6189 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6188 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6180 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 6184 - }, - { - "id" : "minecraft:white_glazed_terracotta", - "blockRuntimeId" : 5575 - }, - { - "id" : "minecraft:silver_glazed_terracotta", - "blockRuntimeId" : 3533 - }, - { - "id" : "minecraft:gray_glazed_terracotta", - "blockRuntimeId" : 8255 - }, - { - "id" : "minecraft:black_glazed_terracotta", - "blockRuntimeId" : 5836 - }, - { - "id" : "minecraft:brown_glazed_terracotta", - "blockRuntimeId" : 3549 - }, - { - "id" : "minecraft:red_glazed_terracotta", - "blockRuntimeId" : 4169 - }, - { - "id" : "minecraft:orange_glazed_terracotta", - "blockRuntimeId" : 1153 - }, - { - "id" : "minecraft:yellow_glazed_terracotta", - "blockRuntimeId" : 915 - }, - { - "id" : "minecraft:lime_glazed_terracotta", - "blockRuntimeId" : 223 - }, - { - "id" : "minecraft:green_glazed_terracotta", - "blockRuntimeId" : 6612 - }, - { - "id" : "minecraft:cyan_glazed_terracotta", - "blockRuntimeId" : 5360 - }, - { - "id" : "minecraft:light_blue_glazed_terracotta", - "blockRuntimeId" : 5473 - }, - { - "id" : "minecraft:blue_glazed_terracotta", - "blockRuntimeId" : 5467 - }, - { - "id" : "minecraft:purple_glazed_terracotta", - "blockRuntimeId" : 7013 - }, - { - "id" : "minecraft:magenta_glazed_terracotta", - "blockRuntimeId" : 967 - }, - { - "id" : "minecraft:pink_glazed_terracotta", - "blockRuntimeId" : 6541 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 7716 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 7718 - }, - { - "id" : "minecraft:packed_mud", - "blockRuntimeId" : 283 - }, - { - "id" : "minecraft:mud_bricks", - "blockRuntimeId" : 6891 - }, - { - "id" : "minecraft:nether_wart_block", - "blockRuntimeId" : 4295 - }, - { - "id" : "minecraft:warped_wart_block", - "blockRuntimeId" : 5907 - }, - { - "id" : "minecraft:shroomlight", - "blockRuntimeId" : 5063 - }, - { - "id" : "minecraft:crimson_nylium", - "blockRuntimeId" : 4191 - }, - { - "id" : "minecraft:warped_nylium", - "blockRuntimeId" : 6351 - }, - { - "id" : "minecraft:basalt", - "blockRuntimeId" : 4351 - }, - { - "id" : "minecraft:polished_basalt", - "blockRuntimeId" : 24 - }, - { - "id" : "minecraft:smooth_basalt", - "blockRuntimeId" : 1159 - }, - { - "id" : "minecraft:soul_soil", - "blockRuntimeId" : 5832 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 5753 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 5754 - }, - { - "id" : "minecraft:farmland", - "blockRuntimeId" : 3914 - }, - { - "id" : "minecraft:grass", - "blockRuntimeId" : 6977 - }, - { - "id" : "minecraft:grass_path", - "blockRuntimeId" : 8083 - }, - { - "id" : "minecraft:podzol", - "blockRuntimeId" : 4652 - }, - { - "id" : "minecraft:mycelium", - "blockRuntimeId" : 3685 - }, - { - "id" : "minecraft:mud", - "blockRuntimeId" : 6686 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 655 - }, - { - "id" : "minecraft:iron_ore", - "blockRuntimeId" : 4692 - }, - { - "id" : "minecraft:gold_ore", - "blockRuntimeId" : 914 - }, - { - "id" : "minecraft:diamond_ore", - "blockRuntimeId" : 4363 - }, - { - "id" : "minecraft:lapis_ore", - "blockRuntimeId" : 7701 - }, - { - "id" : "minecraft:redstone_ore", - "blockRuntimeId" : 4291 - }, - { - "id" : "minecraft:coal_ore", - "blockRuntimeId" : 4289 - }, - { - "id" : "minecraft:copper_ore", - "blockRuntimeId" : 3556 - }, - { - "id" : "minecraft:emerald_ore", - "blockRuntimeId" : 7349 - }, - { - "id" : "minecraft:quartz_ore", - "blockRuntimeId" : 4503 - }, - { - "id" : "minecraft:nether_gold_ore", - "blockRuntimeId" : 27 - }, - { - "id" : "minecraft:ancient_debris", - "blockRuntimeId" : 6109 - }, - { - "id" : "minecraft:deepslate_iron_ore", - "blockRuntimeId" : 7275 - }, - { - "id" : "minecraft:deepslate_gold_ore", - "blockRuntimeId" : 6108 - }, - { - "id" : "minecraft:deepslate_diamond_ore", - "blockRuntimeId" : 8040 - }, - { - "id" : "minecraft:deepslate_lapis_ore", - "blockRuntimeId" : 7264 - }, - { - "id" : "minecraft:deepslate_redstone_ore", - "blockRuntimeId" : 6618 - }, - { - "id" : "minecraft:deepslate_emerald_ore", - "blockRuntimeId" : 6352 - }, - { - "id" : "minecraft:deepslate_coal_ore", - "blockRuntimeId" : 7198 - }, - { - "id" : "minecraft:deepslate_copper_ore", - "blockRuntimeId" : 105 - }, - { - "id" : "minecraft:gravel", - "blockRuntimeId" : 8289 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 656 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 658 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 660 - }, - { - "id" : "minecraft:blackstone", - "blockRuntimeId" : 7587 - }, - { - "id" : "minecraft:deepslate", - "blockRuntimeId" : 253 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 657 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 659 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 661 - }, - { - "id" : "minecraft:polished_blackstone", - "blockRuntimeId" : 3684 - }, - { - "id" : "minecraft:polished_deepslate", - "blockRuntimeId" : 7756 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 4197 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 4198 - }, - { - "id" : "minecraft:cactus", - "blockRuntimeId" : 6988 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 6674 - }, - { - "id" : "minecraft:stripped_oak_log", - "blockRuntimeId" : 7545 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 6675 - }, - { - "id" : "minecraft:stripped_spruce_log", - "blockRuntimeId" : 6290 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 6676 - }, - { - "id" : "minecraft:stripped_birch_log", - "blockRuntimeId" : 5974 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 6677 - }, - { - "id" : "minecraft:stripped_jungle_log", - "blockRuntimeId" : 644 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 3832 - }, - { - "id" : "minecraft:stripped_acacia_log", - "blockRuntimeId" : 5850 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 3833 - }, - { - "id" : "minecraft:stripped_dark_oak_log", - "blockRuntimeId" : 216 - }, - { - "id" : "minecraft:mangrove_log", - "blockRuntimeId" : 350 - }, - { - "id" : "minecraft:stripped_mangrove_log", - "blockRuntimeId" : 8286 - }, - { - "id" : "minecraft:crimson_stem", - "blockRuntimeId" : 5899 - }, - { - "id" : "minecraft:stripped_crimson_stem", - "blockRuntimeId" : 6950 - }, - { - "id" : "minecraft:warped_stem", - "blockRuntimeId" : 6488 - }, - { - "id" : "minecraft:stripped_warped_stem", - "blockRuntimeId" : 7402 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3476 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3482 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3477 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3483 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3478 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3484 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3479 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3485 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3480 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3486 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3481 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 3487 - }, - { - "id" : "minecraft:mangrove_wood", - "blockRuntimeId" : 4163 - }, - { - "id" : "minecraft:stripped_mangrove_wood", - "blockRuntimeId" : 4231 - }, - { - "id" : "minecraft:crimson_hyphae", - "blockRuntimeId" : 4296 - }, - { - "id" : "minecraft:stripped_crimson_hyphae", - "blockRuntimeId" : 6501 - }, - { - "id" : "minecraft:warped_hyphae", - "blockRuntimeId" : 5904 - }, - { - "id" : "minecraft:stripped_warped_hyphae", - "blockRuntimeId" : 5581 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 6092 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 6093 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 6094 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 6095 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 4355 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 4356 - }, - { - "id" : "minecraft:mangrove_leaves", - "blockRuntimeId" : 6668 - }, - { - "id" : "minecraft:azalea_leaves", - "blockRuntimeId" : 7712 - }, - { - "id" : "minecraft:azalea_leaves_flowered", - "blockRuntimeId" : 6341 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 714 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 715 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 716 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 717 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 718 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 719 - }, - { - "id" : "minecraft:mangrove_propagule", - "blockRuntimeId" : 6978 - }, - { - "id" : "minecraft:bee_nest", - "blockRuntimeId" : 5756 - }, - { - "id" : "minecraft:wheat_seeds" - }, - { - "id" : "minecraft:pumpkin_seeds" - }, - { - "id" : "minecraft:melon_seeds" - }, - { - "id" : "minecraft:beetroot_seeds" - }, - { - "id" : "minecraft:wheat" - }, - { - "id" : "minecraft:beetroot" - }, - { - "id" : "minecraft:potato" - }, - { - "id" : "minecraft:poisonous_potato" - }, - { - "id" : "minecraft:carrot" - }, - { - "id" : "minecraft:golden_carrot" - }, - { - "id" : "minecraft:apple" - }, - { - "id" : "minecraft:golden_apple" - }, - { - "id" : "minecraft:enchanted_golden_apple" - }, - { - "id" : "minecraft:melon_block", - "blockRuntimeId" : 394 - }, - { - "id" : "minecraft:melon_slice" - }, - { - "id" : "minecraft:glistering_melon_slice" - }, - { - "id" : "minecraft:sweet_berries" - }, - { - "id" : "minecraft:glow_berries" - }, - { - "id" : "minecraft:pumpkin", - "blockRuntimeId" : 4579 - }, - { - "id" : "minecraft:carved_pumpkin", - "blockRuntimeId" : 7380 - }, - { - "id" : "minecraft:lit_pumpkin", - "blockRuntimeId" : 6687 - }, - { - "id" : "minecraft:honeycomb" - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 931 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5457 - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 930 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5456 - }, - { - "id" : "minecraft:nether_sprouts" - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6494 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6492 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6493 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6491 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6495 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6499 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6497 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6498 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6496 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 6500 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 4618 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 4616 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 4617 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 4615 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 4619 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 69 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 67 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 68 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 66 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 70 - }, - { - "id" : "minecraft:kelp" - }, - { - "id" : "minecraft:seagrass", - "blockRuntimeId" : 246 - }, - { - "id" : "minecraft:crimson_roots", - "blockRuntimeId" : 7575 - }, - { - "id" : "minecraft:warped_roots", - "blockRuntimeId" : 4364 - }, - { - "id" : "minecraft:yellow_flower", - "blockRuntimeId" : 302 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3618 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3619 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3620 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3621 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3622 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3623 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3624 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3625 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3626 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3627 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 3628 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5454 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5455 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5458 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 5459 - }, - { - "id" : "minecraft:wither_rose", - "blockRuntimeId" : 6167 - }, - { - "id" : "minecraft:white_dye" - }, - { - "id" : "minecraft:light_gray_dye" - }, - { - "id" : "minecraft:gray_dye" - }, - { - "id" : "minecraft:black_dye" - }, - { - "id" : "minecraft:brown_dye" - }, - { - "id" : "minecraft:red_dye" - }, - { - "id" : "minecraft:orange_dye" - }, - { - "id" : "minecraft:yellow_dye" - }, - { - "id" : "minecraft:lime_dye" - }, - { - "id" : "minecraft:green_dye" - }, - { - "id" : "minecraft:cyan_dye" - }, - { - "id" : "minecraft:light_blue_dye" - }, - { - "id" : "minecraft:blue_dye" - }, - { - "id" : "minecraft:purple_dye" - }, - { - "id" : "minecraft:magenta_dye" - }, - { - "id" : "minecraft:pink_dye" - }, - { - "id" : "minecraft:ink_sac" - }, - { - "id" : "minecraft:glow_ink_sac" - }, - { - "id" : "minecraft:cocoa_beans" - }, - { - "id" : "minecraft:lapis_lazuli" - }, - { - "id" : "minecraft:bone_meal" - }, - { - "id" : "minecraft:vine", - "blockRuntimeId" : 896 - }, - { - "id" : "minecraft:weeping_vines", - "blockRuntimeId" : 5481 - }, - { - "id" : "minecraft:twisting_vines", - "blockRuntimeId" : 5693 - }, - { - "id" : "minecraft:waterlily", - "blockRuntimeId" : 1160 - }, - { - "id" : "minecraft:deadbush", - "blockRuntimeId" : 4679 - }, - { - "id" : "minecraft:bamboo", - "blockRuntimeId" : 3686 - }, - { - "id" : "minecraft:snow", - "blockRuntimeId" : 4196 - }, - { - "id" : "minecraft:ice", - "blockRuntimeId" : 6691 - }, - { - "id" : "minecraft:packed_ice", - "blockRuntimeId" : 282 - }, - { - "id" : "minecraft:blue_ice", - "blockRuntimeId" : 7029 - }, - { - "id" : "minecraft:snow_layer", - "blockRuntimeId" : 155 - }, - { - "id" : "minecraft:pointed_dripstone", - "blockRuntimeId" : 7418 - }, - { - "id" : "minecraft:dripstone_block", - "blockRuntimeId" : 895 - }, - { - "id" : "minecraft:moss_carpet", - "blockRuntimeId" : 286 - }, - { - "id" : "minecraft:moss_block", - "blockRuntimeId" : 6540 - }, - { - "id" : "minecraft:dirt_with_roots", - "blockRuntimeId" : 5399 - }, - { - "id" : "minecraft:hanging_roots", - "blockRuntimeId" : 205 - }, - { - "id" : "minecraft:mangrove_roots", - "blockRuntimeId" : 6177 - }, - { - "id" : "minecraft:muddy_mangrove_roots", - "blockRuntimeId" : 345 - }, - { - "id" : "minecraft:big_dripleaf", - "blockRuntimeId" : 5982 - }, - { - "id" : "minecraft:small_dripleaf_block", - "blockRuntimeId" : 4322 - }, - { - "id" : "minecraft:spore_blossom", - "blockRuntimeId" : 7314 - }, - { - "id" : "minecraft:azalea", - "blockRuntimeId" : 6890 - }, - { - "id" : "minecraft:flowering_azalea", - "blockRuntimeId" : 5479 - }, - { - "id" : "minecraft:glow_lichen", - "blockRuntimeId" : 5686 - }, - { - "id" : "minecraft:amethyst_block", - "blockRuntimeId" : 290 - }, - { - "id" : "minecraft:budding_amethyst", - "blockRuntimeId" : 7004 - }, - { - "id" : "minecraft:amethyst_cluster", - "blockRuntimeId" : 7812 - }, - { - "id" : "minecraft:large_amethyst_bud", - "blockRuntimeId" : 4730 - }, - { - "id" : "minecraft:medium_amethyst_bud", - "blockRuntimeId" : 4378 - }, - { - "id" : "minecraft:small_amethyst_bud", - "blockRuntimeId" : 304 - }, - { - "id" : "minecraft:tuff", - "blockRuntimeId" : 349 - }, - { - "id" : "minecraft:calcite", - "blockRuntimeId" : 215 - }, - { - "id" : "minecraft:chicken" - }, - { - "id" : "minecraft:porkchop" - }, - { - "id" : "minecraft:beef" - }, - { - "id" : "minecraft:mutton" - }, - { - "id" : "minecraft:rabbit" - }, - { - "id" : "minecraft:cod" - }, - { - "id" : "minecraft:salmon" - }, - { - "id" : "minecraft:tropical_fish" - }, - { - "id" : "minecraft:pufferfish" - }, - { - "id" : "minecraft:brown_mushroom", - "blockRuntimeId" : 3548 - }, - { - "id" : "minecraft:red_mushroom", - "blockRuntimeId" : 4587 - }, - { - "id" : "minecraft:crimson_fungus", - "blockRuntimeId" : 7755 - }, - { - "id" : "minecraft:warped_fungus", - "blockRuntimeId" : 287 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 7364 - }, - { - "id" : "minecraft:red_mushroom_block", - "blockRuntimeId" : 3613 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 7365 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 7350 - }, - { - "id" : "minecraft:egg" - }, - { - "id" : "minecraft:sugar_cane" - }, - { - "id" : "minecraft:sugar" - }, - { - "id" : "minecraft:rotten_flesh" - }, - { - "id" : "minecraft:bone" - }, - { - "id" : "minecraft:web", - "blockRuntimeId" : 6715 - }, - { - "id" : "minecraft:spider_eye" - }, - { - "id" : "minecraft:mob_spawner", - "blockRuntimeId" : 403 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4146 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4147 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4148 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4149 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4150 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 4151 - }, - { - "id" : "minecraft:infested_deepslate", - "blockRuntimeId" : 4643 - }, - { - "id" : "minecraft:dragon_egg", - "blockRuntimeId" : 7273 - }, - { - "id" : "minecraft:turtle_egg", - "blockRuntimeId" : 7999 - }, - { - "id" : "minecraft:frog_spawn", - "blockRuntimeId" : 4401 - }, - { - "id" : "minecraft:pearlescent_froglight", - "blockRuntimeId" : 6437 - }, - { - "id" : "minecraft:verdant_froglight", - "blockRuntimeId" : 6483 - }, - { - "id" : "minecraft:ochre_froglight", - "blockRuntimeId" : 3512 - }, - { - "id" : "minecraft:chicken_spawn_egg" - }, - { - "id" : "minecraft:bee_spawn_egg" - }, - { - "id" : "minecraft:cow_spawn_egg" - }, - { - "id" : "minecraft:pig_spawn_egg" - }, - { - "id" : "minecraft:sheep_spawn_egg" - }, - { - "id" : "minecraft:wolf_spawn_egg" - }, - { - "id" : "minecraft:polar_bear_spawn_egg" - }, - { - "id" : "minecraft:ocelot_spawn_egg" - }, - { - "id" : "minecraft:cat_spawn_egg" - }, - { - "id" : "minecraft:mooshroom_spawn_egg" - }, - { - "id" : "minecraft:bat_spawn_egg" - }, - { - "id" : "minecraft:parrot_spawn_egg" - }, - { - "id" : "minecraft:rabbit_spawn_egg" - }, - { - "id" : "minecraft:llama_spawn_egg" - }, - { - "id" : "minecraft:horse_spawn_egg" - }, - { - "id" : "minecraft:donkey_spawn_egg" - }, - { - "id" : "minecraft:mule_spawn_egg" - }, - { - "id" : "minecraft:skeleton_horse_spawn_egg" - }, - { - "id" : "minecraft:zombie_horse_spawn_egg" - }, - { - "id" : "minecraft:tropical_fish_spawn_egg" - }, - { - "id" : "minecraft:cod_spawn_egg" - }, - { - "id" : "minecraft:pufferfish_spawn_egg" - }, - { - "id" : "minecraft:salmon_spawn_egg" - }, - { - "id" : "minecraft:dolphin_spawn_egg" - }, - { - "id" : "minecraft:turtle_spawn_egg" - }, - { - "id" : "minecraft:panda_spawn_egg" - }, - { - "id" : "minecraft:fox_spawn_egg" - }, - { - "id" : "minecraft:creeper_spawn_egg" - }, - { - "id" : "minecraft:enderman_spawn_egg" - }, - { - "id" : "minecraft:silverfish_spawn_egg" - }, - { - "id" : "minecraft:skeleton_spawn_egg" - }, - { - "id" : "minecraft:wither_skeleton_spawn_egg" - }, - { - "id" : "minecraft:stray_spawn_egg" - }, - { - "id" : "minecraft:slime_spawn_egg" - }, - { - "id" : "minecraft:spider_spawn_egg" - }, - { - "id" : "minecraft:zombie_spawn_egg" - }, - { - "id" : "minecraft:zombie_pigman_spawn_egg" - }, - { - "id" : "minecraft:husk_spawn_egg" - }, - { - "id" : "minecraft:drowned_spawn_egg" - }, - { - "id" : "minecraft:squid_spawn_egg" - }, - { - "id" : "minecraft:glow_squid_spawn_egg" - }, - { - "id" : "minecraft:cave_spider_spawn_egg" - }, - { - "id" : "minecraft:witch_spawn_egg" - }, - { - "id" : "minecraft:guardian_spawn_egg" - }, - { - "id" : "minecraft:elder_guardian_spawn_egg" - }, - { - "id" : "minecraft:endermite_spawn_egg" - }, - { - "id" : "minecraft:magma_cube_spawn_egg" - }, - { - "id" : "minecraft:strider_spawn_egg" - }, - { - "id" : "minecraft:hoglin_spawn_egg" - }, - { - "id" : "minecraft:piglin_spawn_egg" - }, - { - "id" : "minecraft:zoglin_spawn_egg" - }, - { - "id" : "minecraft:piglin_brute_spawn_egg" - }, - { - "id" : "minecraft:goat_spawn_egg" - }, - { - "id" : "minecraft:axolotl_spawn_egg" - }, - { - "id" : "minecraft:warden_spawn_egg" - }, - { - "id" : "minecraft:allay_spawn_egg" - }, - { - "id" : "minecraft:frog_spawn_egg" - }, - { - "id" : "minecraft:tadpole_spawn_egg" - }, - { - "id" : "minecraft:trader_llama_spawn_egg" - }, - { - "id" : "minecraft:ghast_spawn_egg" - }, - { - "id" : "minecraft:blaze_spawn_egg" - }, - { - "id" : "minecraft:shulker_spawn_egg" - }, - { - "id" : "minecraft:vindicator_spawn_egg" - }, - { - "id" : "minecraft:evoker_spawn_egg" - }, - { - "id" : "minecraft:vex_spawn_egg" - }, - { - "id" : "minecraft:villager_spawn_egg" - }, - { - "id" : "minecraft:wandering_trader_spawn_egg" - }, - { - "id" : "minecraft:zombie_villager_spawn_egg" - }, - { - "id" : "minecraft:phantom_spawn_egg" - }, - { - "id" : "minecraft:pillager_spawn_egg" - }, - { - "id" : "minecraft:ravager_spawn_egg" - }, - { - "id" : "minecraft:obsidian", - "blockRuntimeId" : 430 - }, - { - "id" : "minecraft:crying_obsidian", - "blockRuntimeId" : 6724 - }, - { - "id" : "minecraft:bedrock", - "blockRuntimeId" : 7019 - }, - { - "id" : "minecraft:soul_sand", - "blockRuntimeId" : 5833 - }, - { - "id" : "minecraft:netherrack", - "blockRuntimeId" : 7039 - }, - { - "id" : "minecraft:magma", - "blockRuntimeId" : 8011 - }, - { - "id" : "minecraft:nether_wart" - }, - { - "id" : "minecraft:end_stone", - "blockRuntimeId" : 3838 - }, - { - "id" : "minecraft:chorus_flower", - "blockRuntimeId" : 4532 - }, - { - "id" : "minecraft:chorus_plant", - "blockRuntimeId" : 5507 - }, - { - "id" : "minecraft:chorus_fruit" - }, - { - "id" : "minecraft:popped_chorus_fruit" - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 631 - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 632 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5239 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5240 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5241 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5242 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5243 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5244 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5245 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5246 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5247 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 5248 - }, - { - "id" : "minecraft:sculk", - "blockRuntimeId" : 7038 - }, - { - "id" : "minecraft:sculk_vein", - "blockRuntimeId" : 7134 - }, - { - "id" : "minecraft:sculk_catalyst", - "blockRuntimeId" : 3615 - }, - { - "id" : "minecraft:sculk_shrieker", - "blockRuntimeId" : 219 - }, - { - "id" : "minecraft:sculk_sensor", - "blockRuntimeId" : 4391 - }, - { - "id" : "minecraft:reinforced_deepslate", - "blockRuntimeId" : 5834 - }, - { - "id" : "minecraft:leather_helmet" - }, - { - "id" : "minecraft:chainmail_helmet" - }, - { - "id" : "minecraft:iron_helmet" - }, - { - "id" : "minecraft:golden_helmet" - }, - { - "id" : "minecraft:diamond_helmet" - }, - { - "id" : "minecraft:netherite_helmet" - }, - { - "id" : "minecraft:leather_chestplate" - }, - { - "id" : "minecraft:chainmail_chestplate" - }, - { - "id" : "minecraft:iron_chestplate" - }, - { - "id" : "minecraft:golden_chestplate" - }, - { - "id" : "minecraft:diamond_chestplate" - }, - { - "id" : "minecraft:netherite_chestplate" - }, - { - "id" : "minecraft:leather_leggings" - }, - { - "id" : "minecraft:chainmail_leggings" - }, - { - "id" : "minecraft:iron_leggings" - }, - { - "id" : "minecraft:golden_leggings" - }, - { - "id" : "minecraft:diamond_leggings" - }, - { - "id" : "minecraft:netherite_leggings" - }, - { - "id" : "minecraft:leather_boots" - }, - { - "id" : "minecraft:chainmail_boots" - }, - { - "id" : "minecraft:iron_boots" - }, - { - "id" : "minecraft:golden_boots" - }, - { - "id" : "minecraft:diamond_boots" - }, - { - "id" : "minecraft:netherite_boots" - }, - { - "id" : "minecraft:wooden_sword" - }, - { - "id" : "minecraft:stone_sword" - }, - { - "id" : "minecraft:iron_sword" - }, - { - "id" : "minecraft:golden_sword" - }, - { - "id" : "minecraft:diamond_sword" - }, - { - "id" : "minecraft:netherite_sword" - }, - { - "id" : "minecraft:wooden_axe" - }, - { - "id" : "minecraft:stone_axe" - }, - { - "id" : "minecraft:iron_axe" - }, - { - "id" : "minecraft:golden_axe" - }, - { - "id" : "minecraft:diamond_axe" - }, - { - "id" : "minecraft:netherite_axe" - }, - { - "id" : "minecraft:wooden_pickaxe" - }, - { - "id" : "minecraft:stone_pickaxe" - }, - { - "id" : "minecraft:iron_pickaxe" - }, - { - "id" : "minecraft:golden_pickaxe" - }, - { - "id" : "minecraft:diamond_pickaxe" - }, - { - "id" : "minecraft:netherite_pickaxe" - }, - { - "id" : "minecraft:wooden_shovel" - }, - { - "id" : "minecraft:stone_shovel" - }, - { - "id" : "minecraft:iron_shovel" - }, - { - "id" : "minecraft:golden_shovel" - }, - { - "id" : "minecraft:diamond_shovel" - }, - { - "id" : "minecraft:netherite_shovel" - }, - { - "id" : "minecraft:wooden_hoe" - }, - { - "id" : "minecraft:stone_hoe" - }, - { - "id" : "minecraft:iron_hoe" - }, - { - "id" : "minecraft:golden_hoe" - }, - { - "id" : "minecraft:diamond_hoe" - }, - { - "id" : "minecraft:netherite_hoe" - }, - { - "id" : "minecraft:bow" - }, - { - "id" : "minecraft:crossbow" - }, - { - "id" : "minecraft:arrow" - }, - { - "id" : "minecraft:arrow", - "damage" : 6 - }, - { - "id" : "minecraft:arrow", - "damage" : 7 - }, - { - "id" : "minecraft:arrow", - "damage" : 8 - }, - { - "id" : "minecraft:arrow", - "damage" : 9 - }, - { - "id" : "minecraft:arrow", - "damage" : 10 - }, - { - "id" : "minecraft:arrow", - "damage" : 11 - }, - { - "id" : "minecraft:arrow", - "damage" : 12 - }, - { - "id" : "minecraft:arrow", - "damage" : 13 - }, - { - "id" : "minecraft:arrow", - "damage" : 14 - }, - { - "id" : "minecraft:arrow", - "damage" : 15 - }, - { - "id" : "minecraft:arrow", - "damage" : 16 - }, - { - "id" : "minecraft:arrow", - "damage" : 17 - }, - { - "id" : "minecraft:arrow", - "damage" : 18 - }, - { - "id" : "minecraft:arrow", - "damage" : 19 - }, - { - "id" : "minecraft:arrow", - "damage" : 20 - }, - { - "id" : "minecraft:arrow", - "damage" : 21 - }, - { - "id" : "minecraft:arrow", - "damage" : 22 - }, - { - "id" : "minecraft:arrow", - "damage" : 23 - }, - { - "id" : "minecraft:arrow", - "damage" : 24 - }, - { - "id" : "minecraft:arrow", - "damage" : 25 - }, - { - "id" : "minecraft:arrow", - "damage" : 26 - }, - { - "id" : "minecraft:arrow", - "damage" : 27 - }, - { - "id" : "minecraft:arrow", - "damage" : 28 - }, - { - "id" : "minecraft:arrow", - "damage" : 29 - }, - { - "id" : "minecraft:arrow", - "damage" : 30 - }, - { - "id" : "minecraft:arrow", - "damage" : 31 - }, - { - "id" : "minecraft:arrow", - "damage" : 32 - }, - { - "id" : "minecraft:arrow", - "damage" : 33 - }, - { - "id" : "minecraft:arrow", - "damage" : 34 - }, - { - "id" : "minecraft:arrow", - "damage" : 35 - }, - { - "id" : "minecraft:arrow", - "damage" : 36 - }, - { - "id" : "minecraft:arrow", - "damage" : 37 - }, - { - "id" : "minecraft:arrow", - "damage" : 38 - }, - { - "id" : "minecraft:arrow", - "damage" : 39 - }, - { - "id" : "minecraft:arrow", - "damage" : 40 - }, - { - "id" : "minecraft:arrow", - "damage" : 41 - }, - { - "id" : "minecraft:arrow", - "damage" : 42 - }, - { - "id" : "minecraft:arrow", - "damage" : 43 - }, - { - "id" : "minecraft:shield" - }, - { - "id" : "minecraft:cooked_chicken" - }, - { - "id" : "minecraft:cooked_porkchop" - }, - { - "id" : "minecraft:cooked_beef" - }, - { - "id" : "minecraft:cooked_mutton" - }, - { - "id" : "minecraft:cooked_rabbit" - }, - { - "id" : "minecraft:cooked_cod" - }, - { - "id" : "minecraft:cooked_salmon" - }, - { - "id" : "minecraft:bread" - }, - { - "id" : "minecraft:mushroom_stew" - }, - { - "id" : "minecraft:beetroot_soup" - }, - { - "id" : "minecraft:rabbit_stew" - }, - { - "id" : "minecraft:baked_potato" - }, - { - "id" : "minecraft:cookie" - }, - { - "id" : "minecraft:pumpkin_pie" - }, - { - "id" : "minecraft:cake" - }, - { - "id" : "minecraft:dried_kelp" - }, - { - "id" : "minecraft:fishing_rod" - }, - { - "id" : "minecraft:carrot_on_a_stick" - }, - { - "id" : "minecraft:warped_fungus_on_a_stick" - }, - { - "id" : "minecraft:snowball" - }, - { - "id" : "minecraft:shears" - }, - { - "id" : "minecraft:flint_and_steel" - }, - { - "id" : "minecraft:lead" - }, - { - "id" : "minecraft:clock" - }, - { - "id" : "minecraft:compass" - }, - { - "id" : "minecraft:recovery_compass" - }, - { - "id" : "minecraft:goat_horn" - }, - { - "id" : "minecraft:goat_horn", - "damage" : 1 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 2 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 3 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 4 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 5 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 6 - }, - { - "id" : "minecraft:goat_horn", - "damage" : 7 - }, - { - "id" : "minecraft:empty_map" - }, - { - "id" : "minecraft:empty_map", - "damage" : 2 - }, - { - "id" : "minecraft:saddle" - }, - { - "id" : "minecraft:leather_horse_armor" - }, - { - "id" : "minecraft:iron_horse_armor" - }, - { - "id" : "minecraft:golden_horse_armor" - }, - { - "id" : "minecraft:diamond_horse_armor" - }, - { - "id" : "minecraft:trident" - }, - { - "id" : "minecraft:turtle_helmet" - }, - { - "id" : "minecraft:elytra" - }, - { - "id" : "minecraft:totem_of_undying" - }, - { - "id" : "minecraft:glass_bottle" - }, - { - "id" : "minecraft:experience_bottle" - }, - { - "id" : "minecraft:potion" - }, - { - "id" : "minecraft:potion", - "damage" : 1 - }, - { - "id" : "minecraft:potion", - "damage" : 2 - }, - { - "id" : "minecraft:potion", - "damage" : 3 - }, - { - "id" : "minecraft:potion", - "damage" : 4 - }, - { - "id" : "minecraft:potion", - "damage" : 5 - }, - { - "id" : "minecraft:potion", - "damage" : 6 - }, - { - "id" : "minecraft:potion", - "damage" : 7 - }, - { - "id" : "minecraft:potion", - "damage" : 8 - }, - { - "id" : "minecraft:potion", - "damage" : 9 - }, - { - "id" : "minecraft:potion", - "damage" : 10 - }, - { - "id" : "minecraft:potion", - "damage" : 11 - }, - { - "id" : "minecraft:potion", - "damage" : 12 - }, - { - "id" : "minecraft:potion", - "damage" : 13 - }, - { - "id" : "minecraft:potion", - "damage" : 14 - }, - { - "id" : "minecraft:potion", - "damage" : 15 - }, - { - "id" : "minecraft:potion", - "damage" : 16 - }, - { - "id" : "minecraft:potion", - "damage" : 17 - }, - { - "id" : "minecraft:potion", - "damage" : 18 - }, - { - "id" : "minecraft:potion", - "damage" : 19 - }, - { - "id" : "minecraft:potion", - "damage" : 20 - }, - { - "id" : "minecraft:potion", - "damage" : 21 - }, - { - "id" : "minecraft:potion", - "damage" : 22 - }, - { - "id" : "minecraft:potion", - "damage" : 23 - }, - { - "id" : "minecraft:potion", - "damage" : 24 - }, - { - "id" : "minecraft:potion", - "damage" : 25 - }, - { - "id" : "minecraft:potion", - "damage" : 26 - }, - { - "id" : "minecraft:potion", - "damage" : 27 - }, - { - "id" : "minecraft:potion", - "damage" : 28 - }, - { - "id" : "minecraft:potion", - "damage" : 29 - }, - { - "id" : "minecraft:potion", - "damage" : 30 - }, - { - "id" : "minecraft:potion", - "damage" : 31 - }, - { - "id" : "minecraft:potion", - "damage" : 32 - }, - { - "id" : "minecraft:potion", - "damage" : 33 - }, - { - "id" : "minecraft:potion", - "damage" : 34 - }, - { - "id" : "minecraft:potion", - "damage" : 35 - }, - { - "id" : "minecraft:potion", - "damage" : 36 - }, - { - "id" : "minecraft:potion", - "damage" : 37 - }, - { - "id" : "minecraft:potion", - "damage" : 38 - }, - { - "id" : "minecraft:potion", - "damage" : 39 - }, - { - "id" : "minecraft:potion", - "damage" : 40 - }, - { - "id" : "minecraft:potion", - "damage" : 41 - }, - { - "id" : "minecraft:potion", - "damage" : 42 - }, - { - "id" : "minecraft:splash_potion" - }, - { - "id" : "minecraft:splash_potion", - "damage" : 1 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 2 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 3 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 4 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 5 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 6 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 7 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 8 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 9 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 10 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 11 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 12 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 13 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 14 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 15 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 16 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 17 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 18 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 19 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 20 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 21 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 22 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 23 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 24 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 25 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 26 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 27 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 28 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 29 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 30 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 31 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 32 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 33 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 34 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 35 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 36 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 37 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 38 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 39 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 40 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 41 - }, - { - "id" : "minecraft:splash_potion", - "damage" : 42 - }, - { - "id" : "minecraft:lingering_potion" - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 1 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 2 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 3 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 4 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 5 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 6 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 7 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 8 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 9 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 10 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 11 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 12 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 13 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 14 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 15 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 16 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 17 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 18 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 19 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 20 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 21 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 22 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 23 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 24 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 25 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 26 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 27 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 28 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 29 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 30 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 31 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 32 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 33 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 34 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 35 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 36 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 37 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 38 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 39 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 40 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 41 - }, - { - "id" : "minecraft:lingering_potion", - "damage" : 42 - }, - { - "id" : "minecraft:spyglass" - }, - { - "id" : "minecraft:stick" - }, - { - "id" : "minecraft:bed" - }, - { - "id" : "minecraft:bed", - "damage" : 8 - }, - { - "id" : "minecraft:bed", - "damage" : 7 - }, - { - "id" : "minecraft:bed", - "damage" : 15 - }, - { - "id" : "minecraft:bed", - "damage" : 12 - }, - { - "id" : "minecraft:bed", - "damage" : 14 - }, - { - "id" : "minecraft:bed", - "damage" : 1 - }, - { - "id" : "minecraft:bed", - "damage" : 4 - }, - { - "id" : "minecraft:bed", - "damage" : 5 - }, - { - "id" : "minecraft:bed", - "damage" : 13 - }, - { - "id" : "minecraft:bed", - "damage" : 9 - }, - { - "id" : "minecraft:bed", - "damage" : 3 - }, - { - "id" : "minecraft:bed", - "damage" : 11 - }, - { - "id" : "minecraft:bed", - "damage" : 10 - }, - { - "id" : "minecraft:bed", - "damage" : 2 - }, - { - "id" : "minecraft:bed", - "damage" : 6 - }, - { - "id" : "minecraft:torch", - "blockRuntimeId" : 726 - }, - { - "id" : "minecraft:soul_torch", - "blockRuntimeId" : 4646 - }, - { - "id" : "minecraft:sea_pickle", - "blockRuntimeId" : 5857 - }, - { - "id" : "minecraft:lantern", - "blockRuntimeId" : 7076 - }, - { - "id" : "minecraft:soul_lantern", - "blockRuntimeId" : 5751 - }, - { - "id" : "minecraft:candle", - "blockRuntimeId" : 7405 - }, - { - "id" : "minecraft:white_candle", - "blockRuntimeId" : 5302 - }, - { - "id" : "minecraft:orange_candle", - "blockRuntimeId" : 364 - }, - { - "id" : "minecraft:magenta_candle", - "blockRuntimeId" : 420 - }, - { - "id" : "minecraft:light_blue_candle", - "blockRuntimeId" : 4571 - }, - { - "id" : "minecraft:yellow_candle", - "blockRuntimeId" : 6194 - }, - { - "id" : "minecraft:lime_candle", - "blockRuntimeId" : 6370 - }, - { - "id" : "minecraft:pink_candle", - "blockRuntimeId" : 7372 - }, - { - "id" : "minecraft:gray_candle", - "blockRuntimeId" : 941 - }, - { - "id" : "minecraft:light_gray_candle", - "blockRuntimeId" : 6226 - }, - { - "id" : "minecraft:cyan_candle", - "blockRuntimeId" : 7728 - }, - { - "id" : "minecraft:purple_candle", - "blockRuntimeId" : 7040 - }, - { - "id" : "minecraft:blue_candle" - }, - { - "id" : "minecraft:brown_candle", - "blockRuntimeId" : 5877 - }, - { - "id" : "minecraft:green_candle", - "blockRuntimeId" : 688 - }, - { - "id" : "minecraft:red_candle", - "blockRuntimeId" : 4683 - }, - { - "id" : "minecraft:black_candle", - "blockRuntimeId" : 171 - }, - { - "id" : "minecraft:crafting_table", - "blockRuntimeId" : 5856 - }, - { - "id" : "minecraft:cartography_table", - "blockRuntimeId" : 8290 - }, - { - "id" : "minecraft:fletching_table", - "blockRuntimeId" : 5835 - }, - { - "id" : "minecraft:smithing_table", - "blockRuntimeId" : 3728 - }, - { - "id" : "minecraft:beehive", - "blockRuntimeId" : 6110 - }, - { - "id" : "minecraft:campfire" - }, - { - "id" : "minecraft:soul_campfire" - }, - { - "id" : "minecraft:furnace", - "blockRuntimeId" : 7804 - }, - { - "id" : "minecraft:blast_furnace", - "blockRuntimeId" : 7569 - }, - { - "id" : "minecraft:smoker", - "blockRuntimeId" : 649 - }, - { - "id" : "minecraft:respawn_anchor", - "blockRuntimeId" : 683 - }, - { - "id" : "minecraft:brewing_stand" - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 6636 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 6640 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 6644 - }, - { - "id" : "minecraft:grindstone", - "blockRuntimeId" : 8041 - }, - { - "id" : "minecraft:enchanting_table", - "blockRuntimeId" : 6725 - }, - { - "id" : "minecraft:bookshelf", - "blockRuntimeId" : 6673 - }, - { - "id" : "minecraft:lectern", - "blockRuntimeId" : 6942 - }, - { - "id" : "minecraft:cauldron" - }, - { - "id" : "minecraft:composter", - "blockRuntimeId" : 5417 - }, - { - "id" : "minecraft:chest", - "blockRuntimeId" : 7117 - }, - { - "id" : "minecraft:trapped_chest", - "blockRuntimeId" : 5585 - }, - { - "id" : "minecraft:ender_chest", - "blockRuntimeId" : 4371 - }, - { - "id" : "minecraft:barrel", - "blockRuntimeId" : 4520 - }, - { - "id" : "minecraft:undyed_shulker_box", - "blockRuntimeId" : 3683 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5318 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5326 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5325 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5333 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5330 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5332 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5319 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5322 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5323 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5331 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5327 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5321 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5329 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5328 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5320 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 5324 - }, - { - "id" : "minecraft:armor_stand" - }, - { - "id" : "minecraft:noteblock", - "blockRuntimeId" : 348 - }, - { - "id" : "minecraft:jukebox", - "blockRuntimeId" : 4876 - }, - { - "id" : "minecraft:music_disc_13" - }, - { - "id" : "minecraft:music_disc_cat" - }, - { - "id" : "minecraft:music_disc_blocks" - }, - { - "id" : "minecraft:music_disc_chirp" - }, - { - "id" : "minecraft:music_disc_far" - }, - { - "id" : "minecraft:music_disc_mall" - }, - { - "id" : "minecraft:music_disc_mellohi" - }, - { - "id" : "minecraft:music_disc_stal" - }, - { - "id" : "minecraft:music_disc_strad" - }, - { - "id" : "minecraft:music_disc_ward" - }, - { - "id" : "minecraft:music_disc_11" - }, - { - "id" : "minecraft:music_disc_wait" - }, - { - "id" : "minecraft:music_disc_otherside" - }, - { - "id" : "minecraft:music_disc_5" - }, - { - "id" : "minecraft:music_disc_pigstep" - }, - { - "id" : "minecraft:disc_fragment_5" - }, - { - "id" : "minecraft:glowstone_dust" - }, - { - "id" : "minecraft:glowstone", - "blockRuntimeId" : 3887 - }, - { - "id" : "minecraft:redstone_lamp", - "blockRuntimeId" : 251 - }, - { - "id" : "minecraft:sea_lantern", - "blockRuntimeId" : 7548 - }, - { - "id" : "minecraft:oak_sign" - }, - { - "id" : "minecraft:spruce_sign" - }, - { - "id" : "minecraft:birch_sign" - }, - { - "id" : "minecraft:jungle_sign" - }, - { - "id" : "minecraft:acacia_sign" - }, - { - "id" : "minecraft:dark_oak_sign" - }, - { - "id" : "minecraft:mangrove_sign" - }, - { - "id" : "minecraft:crimson_sign" - }, - { - "id" : "minecraft:warped_sign" - }, - { - "id" : "minecraft:painting" - }, - { - "id" : "minecraft:frame" - }, - { - "id" : "minecraft:glow_frame" - }, - { - "id" : "minecraft:honey_bottle" - }, - { - "id" : "minecraft:flower_pot" - }, - { - "id" : "minecraft:bowl" - }, - { - "id" : "minecraft:bucket" - }, - { - "id" : "minecraft:milk_bucket" - }, - { - "id" : "minecraft:water_bucket" - }, - { - "id" : "minecraft:lava_bucket" - }, - { - "id" : "minecraft:cod_bucket" - }, - { - "id" : "minecraft:salmon_bucket" - }, - { - "id" : "minecraft:tropical_fish_bucket" - }, - { - "id" : "minecraft:pufferfish_bucket" - }, - { - "id" : "minecraft:powder_snow_bucket" - }, - { - "id" : "minecraft:axolotl_bucket" - }, - { - "id" : "minecraft:tadpole_bucket" - }, - { - "id" : "minecraft:skull", - "damage" : 3 - }, - { - "id" : "minecraft:skull", - "damage" : 2 - }, - { - "id" : "minecraft:skull", - "damage" : 4 - }, - { - "id" : "minecraft:skull", - "damage" : 5 - }, - { - "id" : "minecraft:skull" - }, - { - "id" : "minecraft:skull", - "damage" : 1 - }, - { - "id" : "minecraft:beacon", - "blockRuntimeId" : 145 - }, - { - "id" : "minecraft:bell", - "blockRuntimeId" : 6910 - }, - { - "id" : "minecraft:conduit", - "blockRuntimeId" : 4234 - }, - { - "id" : "minecraft:stonecutter_block", - "blockRuntimeId" : 7576 - }, - { - "id" : "minecraft:end_portal_frame", - "blockRuntimeId" : 6079 - }, - { - "id" : "minecraft:coal" - }, - { - "id" : "minecraft:charcoal" - }, - { - "id" : "minecraft:diamond" - }, - { - "id" : "minecraft:iron_nugget" - }, - { - "id" : "minecraft:raw_iron" - }, - { - "id" : "minecraft:raw_gold" - }, - { - "id" : "minecraft:raw_copper" - }, - { - "id" : "minecraft:copper_ingot" - }, - { - "id" : "minecraft:iron_ingot" - }, - { - "id" : "minecraft:netherite_scrap" - }, - { - "id" : "minecraft:netherite_ingot" - }, - { - "id" : "minecraft:gold_nugget" - }, - { - "id" : "minecraft:gold_ingot" - }, - { - "id" : "minecraft:emerald" - }, - { - "id" : "minecraft:quartz" - }, - { - "id" : "minecraft:clay_ball" - }, - { - "id" : "minecraft:brick" - }, - { - "id" : "minecraft:netherbrick" - }, - { - "id" : "minecraft:prismarine_shard" - }, - { - "id" : "minecraft:amethyst_shard" - }, - { - "id" : "minecraft:prismarine_crystals" - }, - { - "id" : "minecraft:nautilus_shell" - }, - { - "id" : "minecraft:heart_of_the_sea" - }, - { - "id" : "minecraft:scute" - }, - { - "id" : "minecraft:phantom_membrane" - }, - { - "id" : "minecraft:string" - }, - { - "id" : "minecraft:feather" - }, - { - "id" : "minecraft:flint" - }, - { - "id" : "minecraft:gunpowder" - }, - { - "id" : "minecraft:leather" - }, - { - "id" : "minecraft:rabbit_hide" - }, - { - "id" : "minecraft:rabbit_foot" - }, - { - "id" : "minecraft:fire_charge" - }, - { - "id" : "minecraft:blaze_rod" - }, - { - "id" : "minecraft:blaze_powder" - }, - { - "id" : "minecraft:magma_cream" - }, - { - "id" : "minecraft:fermented_spider_eye" - }, - { - "id" : "minecraft:echo_shard" - }, - { - "id" : "minecraft:dragon_breath" - }, - { - "id" : "minecraft:shulker_shell" - }, - { - "id" : "minecraft:ghast_tear" - }, - { - "id" : "minecraft:slime_ball" - }, - { - "id" : "minecraft:ender_pearl" - }, - { - "id" : "minecraft:ender_eye" - }, - { - "id" : "minecraft:nether_star" - }, - { - "id" : "minecraft:end_rod", - "blockRuntimeId" : 5893 - }, - { - "id" : "minecraft:lightning_rod", - "blockRuntimeId" : 1178 - }, - { - "id" : "minecraft:end_crystal" - }, - { - "id" : "minecraft:paper" - }, - { - "id" : "minecraft:book" - }, - { - "id" : "minecraft:writable_book" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" - }, - { - "id" : "minecraft:enchanted_book", - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" - }, - { - "id" : "minecraft:oak_boat" - }, - { - "id" : "minecraft:spruce_boat" - }, - { - "id" : "minecraft:birch_boat" - }, - { - "id" : "minecraft:jungle_boat" - }, - { - "id" : "minecraft:acacia_boat" - }, - { - "id" : "minecraft:dark_oak_boat" - }, - { - "id" : "minecraft:mangrove_boat" - }, - { - "id" : "minecraft:oak_chest_boat" - }, - { - "id" : "minecraft:spruce_chest_boat" - }, - { - "id" : "minecraft:birch_chest_boat" - }, - { - "id" : "minecraft:jungle_chest_boat" - }, - { - "id" : "minecraft:acacia_chest_boat" - }, - { - "id" : "minecraft:dark_oak_chest_boat" - }, - { - "id" : "minecraft:mangrove_chest_boat" - }, - { - "id" : "minecraft:rail", - "blockRuntimeId" : 3922 - }, - { - "id" : "minecraft:golden_rail", - "blockRuntimeId" : 5334 - }, - { - "id" : "minecraft:detector_rail", - "blockRuntimeId" : 4134 - }, - { - "id" : "minecraft:activator_rail", - "blockRuntimeId" : 309 - }, - { - "id" : "minecraft:minecart" - }, - { - "id" : "minecraft:chest_minecart" - }, - { - "id" : "minecraft:hopper_minecart" - }, - { - "id" : "minecraft:tnt_minecart" - }, - { - "id" : "minecraft:redstone" - }, - { - "id" : "minecraft:redstone_block", - "blockRuntimeId" : 3778 - }, - { - "id" : "minecraft:redstone_torch", - "blockRuntimeId" : 3527 - }, - { - "id" : "minecraft:lever", - "blockRuntimeId" : 6516 - }, - { - "id" : "minecraft:wooden_button", - "blockRuntimeId" : 6393 - }, - { - "id" : "minecraft:spruce_button", - "blockRuntimeId" : 4323 - }, - { - "id" : "minecraft:birch_button", - "blockRuntimeId" : 7768 - }, - { - "id" : "minecraft:jungle_button", - "blockRuntimeId" : 116 - }, - { - "id" : "minecraft:acacia_button", - "blockRuntimeId" : 7233 - }, - { - "id" : "minecraft:dark_oak_button", - "blockRuntimeId" : 93 - }, - { - "id" : "minecraft:mangrove_button", - "blockRuntimeId" : 7064 - }, - { - "id" : "minecraft:stone_button", - "blockRuntimeId" : 598 - }, - { - "id" : "minecraft:crimson_button", - "blockRuntimeId" : 4434 - }, - { - "id" : "minecraft:warped_button", - "blockRuntimeId" : 7252 - }, - { - "id" : "minecraft:polished_blackstone_button", - "blockRuntimeId" : 7792 - }, - { - "id" : "minecraft:tripwire_hook", - "blockRuntimeId" : 5916 - }, - { - "id" : "minecraft:wooden_pressure_plate", - "blockRuntimeId" : 8065 - }, - { - "id" : "minecraft:spruce_pressure_plate", - "blockRuntimeId" : 3761 - }, - { - "id" : "minecraft:birch_pressure_plate", - "blockRuntimeId" : 3557 - }, - { - "id" : "minecraft:jungle_pressure_plate", - "blockRuntimeId" : 3637 - }, - { - "id" : "minecraft:acacia_pressure_plate", - "blockRuntimeId" : 5249 - }, - { - "id" : "minecraft:dark_oak_pressure_plate", - "blockRuntimeId" : 5958 - }, - { - "id" : "minecraft:mangrove_pressure_plate", - "blockRuntimeId" : 3871 - }, - { - "id" : "minecraft:crimson_pressure_plate", - "blockRuntimeId" : 8270 - }, - { - "id" : "minecraft:warped_pressure_plate", - "blockRuntimeId" : 256 - }, - { - "id" : "minecraft:stone_pressure_plate", - "blockRuntimeId" : 3888 - }, - { - "id" : "minecraft:light_weighted_pressure_plate", - "blockRuntimeId" : 3667 - }, - { - "id" : "minecraft:heavy_weighted_pressure_plate", - "blockRuntimeId" : 1162 - }, - { - "id" : "minecraft:polished_blackstone_pressure_plate", - "blockRuntimeId" : 6234 - }, - { - "id" : "minecraft:observer", - "blockRuntimeId" : 3515 - }, - { - "id" : "minecraft:daylight_detector", - "blockRuntimeId" : 4199 - }, - { - "id" : "minecraft:repeater" - }, - { - "id" : "minecraft:comparator" - }, - { - "id" : "minecraft:hopper" - }, - { - "id" : "minecraft:dropper", - "blockRuntimeId" : 7387 - }, - { - "id" : "minecraft:dispenser", - "blockRuntimeId" : 8015 - }, - { - "id" : "minecraft:piston", - "blockRuntimeId" : 924 - }, - { - "id" : "minecraft:sticky_piston", - "blockRuntimeId" : 4366 - }, - { - "id" : "minecraft:tnt", - "blockRuntimeId" : 6709 - }, - { - "id" : "minecraft:name_tag" - }, - { - "id" : "minecraft:loom", - "blockRuntimeId" : 3828 - }, - { - "id" : "minecraft:banner" - }, - { - "id" : "minecraft:banner", - "damage" : 8 - }, - { - "id" : "minecraft:banner", - "damage" : 7 - }, - { - "id" : "minecraft:banner", - "damage" : 15 - }, - { - "id" : "minecraft:banner", - "damage" : 12 - }, - { - "id" : "minecraft:banner", - "damage" : 14 - }, - { - "id" : "minecraft:banner", - "damage" : 1 - }, - { - "id" : "minecraft:banner", - "damage" : 4 - }, - { - "id" : "minecraft:banner", - "damage" : 5 - }, - { - "id" : "minecraft:banner", - "damage" : 13 - }, - { - "id" : "minecraft:banner", - "damage" : 9 - }, - { - "id" : "minecraft:banner", - "damage" : 3 - }, - { - "id" : "minecraft:banner", - "damage" : 11 - }, - { - "id" : "minecraft:banner", - "damage" : 10 - }, - { - "id" : "minecraft:banner", - "damage" : 2 - }, - { - "id" : "minecraft:banner", - "damage" : 6 - }, - { - "id" : "minecraft:banner", - "damage" : 15, - "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" - }, - { - "id" : "minecraft:creeper_banner_pattern" - }, - { - "id" : "minecraft:skull_banner_pattern" - }, - { - "id" : "minecraft:flower_banner_pattern" - }, - { - "id" : "minecraft:mojang_banner_pattern" - }, - { - "id" : "minecraft:field_masoned_banner_pattern" - }, - { - "id" : "minecraft:bordure_indented_banner_pattern" - }, - { - "id" : "minecraft:piglin_banner_pattern" - }, - { - "id" : "minecraft:globe_banner_pattern" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_rocket", - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" - }, - { - "id" : "minecraft:firework_star", - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 8, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 7, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 15, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 12, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 14, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 1, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 4, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 5, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 13, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 9, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 3, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 11, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 10, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 2, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" - }, - { - "id" : "minecraft:firework_star", - "damage" : 6, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" - }, - { - "id" : "minecraft:chain" - }, - { - "id" : "minecraft:target", - "blockRuntimeId" : 6392 - }, - { - "id" : "minecraft:lodestone_compass" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json deleted file mode 100644 index 00be1af06..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json +++ /dev/null @@ -1,4530 +0,0 @@ -[ - { - "name" : "minecraft:acacia_boat", - "id" : 379 - }, - { - "name" : "minecraft:acacia_button", - "id" : -140 - }, - { - "name" : "minecraft:acacia_chest_boat", - "id" : 642 - }, - { - "name" : "minecraft:acacia_door", - "id" : 556 - }, - { - "name" : "minecraft:acacia_fence_gate", - "id" : 187 - }, - { - "name" : "minecraft:acacia_pressure_plate", - "id" : -150 - }, - { - "name" : "minecraft:acacia_sign", - "id" : 579 - }, - { - "name" : "minecraft:acacia_stairs", - "id" : 163 - }, - { - "name" : "minecraft:acacia_standing_sign", - "id" : -190 - }, - { - "name" : "minecraft:acacia_trapdoor", - "id" : -145 - }, - { - "name" : "minecraft:acacia_wall_sign", - "id" : -191 - }, - { - "name" : "minecraft:activator_rail", - "id" : 126 - }, - { - "name" : "minecraft:agent_spawn_egg", - "id" : 487 - }, - { - "name" : "minecraft:air", - "id" : -158 - }, - { - "name" : "minecraft:allay_spawn_egg", - "id" : 631 - }, - { - "name" : "minecraft:allow", - "id" : 210 - }, - { - "name" : "minecraft:amethyst_block", - "id" : -327 - }, - { - "name" : "minecraft:amethyst_cluster", - "id" : -329 - }, - { - "name" : "minecraft:amethyst_shard", - "id" : 624 - }, - { - "name" : "minecraft:ancient_debris", - "id" : -271 - }, - { - "name" : "minecraft:andesite_stairs", - "id" : -171 - }, - { - "name" : "minecraft:anvil", - "id" : 145 - }, - { - "name" : "minecraft:apple", - "id" : 257 - }, - { - "name" : "minecraft:armor_stand", - "id" : 552 - }, - { - "name" : "minecraft:arrow", - "id" : 301 - }, - { - "name" : "minecraft:axolotl_bucket", - "id" : 369 - }, - { - "name" : "minecraft:axolotl_spawn_egg", - "id" : 500 - }, - { - "name" : "minecraft:azalea", - "id" : -337 - }, - { - "name" : "minecraft:azalea_leaves", - "id" : -324 - }, - { - "name" : "minecraft:azalea_leaves_flowered", - "id" : -325 - }, - { - "name" : "minecraft:baked_potato", - "id" : 281 - }, - { - "name" : "minecraft:balloon", - "id" : 598 - }, - { - "name" : "minecraft:bamboo", - "id" : -163 - }, - { - "name" : "minecraft:bamboo_sapling", - "id" : -164 - }, - { - "name" : "minecraft:banner", - "id" : 567 - }, - { - "name" : "minecraft:banner_pattern", - "id" : 651 - }, - { - "name" : "minecraft:barrel", - "id" : -203 - }, - { - "name" : "minecraft:barrier", - "id" : -161 - }, - { - "name" : "minecraft:basalt", - "id" : -234 - }, - { - "name" : "minecraft:bat_spawn_egg", - "id" : 453 - }, - { - "name" : "minecraft:beacon", - "id" : 138 - }, - { - "name" : "minecraft:bed", - "id" : 418 - }, - { - "name" : "minecraft:bedrock", - "id" : 7 - }, - { - "name" : "minecraft:bee_nest", - "id" : -218 - }, - { - "name" : "minecraft:bee_spawn_egg", - "id" : 494 - }, - { - "name" : "minecraft:beef", - "id" : 273 - }, - { - "name" : "minecraft:beehive", - "id" : -219 - }, - { - "name" : "minecraft:beetroot", - "id" : 285 - }, - { - "name" : "minecraft:beetroot_seeds", - "id" : 295 - }, - { - "name" : "minecraft:beetroot_soup", - "id" : 286 - }, - { - "name" : "minecraft:bell", - "id" : -206 - }, - { - "name" : "minecraft:big_dripleaf", - "id" : -323 - }, - { - "name" : "minecraft:birch_boat", - "id" : 376 - }, - { - "name" : "minecraft:birch_button", - "id" : -141 - }, - { - "name" : "minecraft:birch_chest_boat", - "id" : 639 - }, - { - "name" : "minecraft:birch_door", - "id" : 554 - }, - { - "name" : "minecraft:birch_fence_gate", - "id" : 184 - }, - { - "name" : "minecraft:birch_pressure_plate", - "id" : -151 - }, - { - "name" : "minecraft:birch_sign", - "id" : 577 - }, - { - "name" : "minecraft:birch_stairs", - "id" : 135 - }, - { - "name" : "minecraft:birch_standing_sign", - "id" : -186 - }, - { - "name" : "minecraft:birch_trapdoor", - "id" : -146 - }, - { - "name" : "minecraft:birch_wall_sign", - "id" : -187 - }, - { - "name" : "minecraft:black_candle", - "id" : -428 - }, - { - "name" : "minecraft:black_candle_cake", - "id" : -445 - }, - { - "name" : "minecraft:black_dye", - "id" : 395 - }, - { - "name" : "minecraft:black_glazed_terracotta", - "id" : 235 - }, - { - "name" : "minecraft:blackstone", - "id" : -273 - }, - { - "name" : "minecraft:blackstone_double_slab", - "id" : -283 - }, - { - "name" : "minecraft:blackstone_slab", - "id" : -282 - }, - { - "name" : "minecraft:blackstone_stairs", - "id" : -276 - }, - { - "name" : "minecraft:blackstone_wall", - "id" : -277 - }, - { - "name" : "minecraft:blast_furnace", - "id" : -196 - }, - { - "name" : "minecraft:blaze_powder", - "id" : 429 - }, - { - "name" : "minecraft:blaze_rod", - "id" : 423 - }, - { - "name" : "minecraft:blaze_spawn_egg", - "id" : 456 - }, - { - "name" : "minecraft:bleach", - "id" : 596 - }, - { - "name" : "minecraft:blue_candle", - "id" : -424 - }, - { - "name" : "minecraft:blue_candle_cake", - "id" : -441 - }, - { - "name" : "minecraft:blue_dye", - "id" : 399 - }, - { - "name" : "minecraft:blue_glazed_terracotta", - "id" : 231 - }, - { - "name" : "minecraft:blue_ice", - "id" : -11 - }, - { - "name" : "minecraft:boat", - "id" : 649 - }, - { - "name" : "minecraft:bone", - "id" : 415 - }, - { - "name" : "minecraft:bone_block", - "id" : 216 - }, - { - "name" : "minecraft:bone_meal", - "id" : 411 - }, - { - "name" : "minecraft:book", - "id" : 387 - }, - { - "name" : "minecraft:bookshelf", - "id" : 47 - }, - { - "name" : "minecraft:border_block", - "id" : 212 - }, - { - "name" : "minecraft:bordure_indented_banner_pattern", - "id" : 586 - }, - { - "name" : "minecraft:bow", - "id" : 300 - }, - { - "name" : "minecraft:bowl", - "id" : 321 - }, - { - "name" : "minecraft:bread", - "id" : 261 - }, - { - "name" : "minecraft:brewing_stand", - "id" : 431 - }, - { - "name" : "minecraft:brick", - "id" : 383 - }, - { - "name" : "minecraft:brick_block", - "id" : 45 - }, - { - "name" : "minecraft:brick_stairs", - "id" : 108 - }, - { - "name" : "minecraft:brown_candle", - "id" : -425 - }, - { - "name" : "minecraft:brown_candle_cake", - "id" : -442 - }, - { - "name" : "minecraft:brown_dye", - "id" : 398 - }, - { - "name" : "minecraft:brown_glazed_terracotta", - "id" : 232 - }, - { - "name" : "minecraft:brown_mushroom", - "id" : 39 - }, - { - "name" : "minecraft:brown_mushroom_block", - "id" : 99 - }, - { - "name" : "minecraft:bubble_column", - "id" : -160 - }, - { - "name" : "minecraft:bucket", - "id" : 360 - }, - { - "name" : "minecraft:budding_amethyst", - "id" : -328 - }, - { - "name" : "minecraft:cactus", - "id" : 81 - }, - { - "name" : "minecraft:cake", - "id" : 417 - }, - { - "name" : "minecraft:calcite", - "id" : -326 - }, - { - "name" : "minecraft:camera", - "id" : 593 - }, - { - "name" : "minecraft:campfire", - "id" : 589 - }, - { - "name" : "minecraft:candle", - "id" : -412 - }, - { - "name" : "minecraft:candle_cake", - "id" : -429 - }, - { - "name" : "minecraft:carpet", - "id" : 171 - }, - { - "name" : "minecraft:carrot", - "id" : 279 - }, - { - "name" : "minecraft:carrot_on_a_stick", - "id" : 517 - }, - { - "name" : "minecraft:carrots", - "id" : 141 - }, - { - "name" : "minecraft:cartography_table", - "id" : -200 - }, - { - "name" : "minecraft:carved_pumpkin", - "id" : -155 - }, - { - "name" : "minecraft:cat_spawn_egg", - "id" : 488 - }, - { - "name" : "minecraft:cauldron", - "id" : 432 - }, - { - "name" : "minecraft:cave_spider_spawn_egg", - "id" : 457 - }, - { - "name" : "minecraft:cave_vines", - "id" : -322 - }, - { - "name" : "minecraft:cave_vines_body_with_berries", - "id" : -375 - }, - { - "name" : "minecraft:cave_vines_head_with_berries", - "id" : -376 - }, - { - "name" : "minecraft:chain", - "id" : 619 - }, - { - "name" : "minecraft:chain_command_block", - "id" : 189 - }, - { - "name" : "minecraft:chainmail_boots", - "id" : 342 - }, - { - "name" : "minecraft:chainmail_chestplate", - "id" : 340 - }, - { - "name" : "minecraft:chainmail_helmet", - "id" : 339 - }, - { - "name" : "minecraft:chainmail_leggings", - "id" : 341 - }, - { - "name" : "minecraft:charcoal", - "id" : 303 - }, - { - "name" : "minecraft:chemical_heat", - "id" : 192 - }, - { - "name" : "minecraft:chemistry_table", - "id" : 238 - }, - { - "name" : "minecraft:chest", - "id" : 54 - }, - { - "name" : "minecraft:chest_boat", - "id" : 645 - }, - { - "name" : "minecraft:chest_minecart", - "id" : 389 - }, - { - "name" : "minecraft:chicken", - "id" : 275 - }, - { - "name" : "minecraft:chicken_spawn_egg", - "id" : 435 - }, - { - "name" : "minecraft:chiseled_deepslate", - "id" : -395 - }, - { - "name" : "minecraft:chiseled_nether_bricks", - "id" : -302 - }, - { - "name" : "minecraft:chiseled_polished_blackstone", - "id" : -279 - }, - { - "name" : "minecraft:chorus_flower", - "id" : 200 - }, - { - "name" : "minecraft:chorus_fruit", - "id" : 558 - }, - { - "name" : "minecraft:chorus_plant", - "id" : 240 - }, - { - "name" : "minecraft:clay", - "id" : 82 - }, - { - "name" : "minecraft:clay_ball", - "id" : 384 - }, - { - "name" : "minecraft:client_request_placeholder_block", - "id" : -465 - }, - { - "name" : "minecraft:clock", - "id" : 393 - }, - { - "name" : "minecraft:coal", - "id" : 302 - }, - { - "name" : "minecraft:coal_block", - "id" : 173 - }, - { - "name" : "minecraft:coal_ore", - "id" : 16 - }, - { - "name" : "minecraft:cobbled_deepslate", - "id" : -379 - }, - { - "name" : "minecraft:cobbled_deepslate_double_slab", - "id" : -396 - }, - { - "name" : "minecraft:cobbled_deepslate_slab", - "id" : -380 - }, - { - "name" : "minecraft:cobbled_deepslate_stairs", - "id" : -381 - }, - { - "name" : "minecraft:cobbled_deepslate_wall", - "id" : -382 - }, - { - "name" : "minecraft:cobblestone", - "id" : 4 - }, - { - "name" : "minecraft:cobblestone_wall", - "id" : 139 - }, - { - "name" : "minecraft:cocoa", - "id" : 127 - }, - { - "name" : "minecraft:cocoa_beans", - "id" : 412 - }, - { - "name" : "minecraft:cod", - "id" : 264 - }, - { - "name" : "minecraft:cod_bucket", - "id" : 364 - }, - { - "name" : "minecraft:cod_spawn_egg", - "id" : 480 - }, - { - "name" : "minecraft:colored_torch_bp", - "id" : 204 - }, - { - "name" : "minecraft:colored_torch_rg", - "id" : 202 - }, - { - "name" : "minecraft:command_block", - "id" : 137 - }, - { - "name" : "minecraft:command_block_minecart", - "id" : 563 - }, - { - "name" : "minecraft:comparator", - "id" : 522 - }, - { - "name" : "minecraft:compass", - "id" : 391 - }, - { - "name" : "minecraft:composter", - "id" : -213 - }, - { - "name" : "minecraft:compound", - "id" : 594 - }, - { - "name" : "minecraft:concrete", - "id" : 236 - }, - { - "name" : "minecraft:concrete_powder", - "id" : 237 - }, - { - "name" : "minecraft:conduit", - "id" : -157 - }, - { - "name" : "minecraft:cooked_beef", - "id" : 274 - }, - { - "name" : "minecraft:cooked_chicken", - "id" : 276 - }, - { - "name" : "minecraft:cooked_cod", - "id" : 268 - }, - { - "name" : "minecraft:cooked_mutton", - "id" : 551 - }, - { - "name" : "minecraft:cooked_porkchop", - "id" : 263 - }, - { - "name" : "minecraft:cooked_rabbit", - "id" : 289 - }, - { - "name" : "minecraft:cooked_salmon", - "id" : 269 - }, - { - "name" : "minecraft:cookie", - "id" : 271 - }, - { - "name" : "minecraft:copper_block", - "id" : -340 - }, - { - "name" : "minecraft:copper_ingot", - "id" : 504 - }, - { - "name" : "minecraft:copper_ore", - "id" : -311 - }, - { - "name" : "minecraft:coral", - "id" : -131 - }, - { - "name" : "minecraft:coral_block", - "id" : -132 - }, - { - "name" : "minecraft:coral_fan", - "id" : -133 - }, - { - "name" : "minecraft:coral_fan_dead", - "id" : -134 - }, - { - "name" : "minecraft:coral_fan_hang", - "id" : -135 - }, - { - "name" : "minecraft:coral_fan_hang2", - "id" : -136 - }, - { - "name" : "minecraft:coral_fan_hang3", - "id" : -137 - }, - { - "name" : "minecraft:cow_spawn_egg", - "id" : 436 - }, - { - "name" : "minecraft:cracked_deepslate_bricks", - "id" : -410 - }, - { - "name" : "minecraft:cracked_deepslate_tiles", - "id" : -409 - }, - { - "name" : "minecraft:cracked_nether_bricks", - "id" : -303 - }, - { - "name" : "minecraft:cracked_polished_blackstone_bricks", - "id" : -280 - }, - { - "name" : "minecraft:crafting_table", - "id" : 58 - }, - { - "name" : "minecraft:creeper_banner_pattern", - "id" : 582 - }, - { - "name" : "minecraft:creeper_spawn_egg", - "id" : 441 - }, - { - "name" : "minecraft:crimson_button", - "id" : -260 - }, - { - "name" : "minecraft:crimson_door", - "id" : 616 - }, - { - "name" : "minecraft:crimson_double_slab", - "id" : -266 - }, - { - "name" : "minecraft:crimson_fence", - "id" : -256 - }, - { - "name" : "minecraft:crimson_fence_gate", - "id" : -258 - }, - { - "name" : "minecraft:crimson_fungus", - "id" : -228 - }, - { - "name" : "minecraft:crimson_hyphae", - "id" : -299 - }, - { - "name" : "minecraft:crimson_nylium", - "id" : -232 - }, - { - "name" : "minecraft:crimson_planks", - "id" : -242 - }, - { - "name" : "minecraft:crimson_pressure_plate", - "id" : -262 - }, - { - "name" : "minecraft:crimson_roots", - "id" : -223 - }, - { - "name" : "minecraft:crimson_sign", - "id" : 614 - }, - { - "name" : "minecraft:crimson_slab", - "id" : -264 - }, - { - "name" : "minecraft:crimson_stairs", - "id" : -254 - }, - { - "name" : "minecraft:crimson_standing_sign", - "id" : -250 - }, - { - "name" : "minecraft:crimson_stem", - "id" : -225 - }, - { - "name" : "minecraft:crimson_trapdoor", - "id" : -246 - }, - { - "name" : "minecraft:crimson_wall_sign", - "id" : -252 - }, - { - "name" : "minecraft:crossbow", - "id" : 575 - }, - { - "name" : "minecraft:crying_obsidian", - "id" : -289 - }, - { - "name" : "minecraft:cut_copper", - "id" : -347 - }, - { - "name" : "minecraft:cut_copper_slab", - "id" : -361 - }, - { - "name" : "minecraft:cut_copper_stairs", - "id" : -354 - }, - { - "name" : "minecraft:cyan_candle", - "id" : -422 - }, - { - "name" : "minecraft:cyan_candle_cake", - "id" : -439 - }, - { - "name" : "minecraft:cyan_dye", - "id" : 401 - }, - { - "name" : "minecraft:cyan_glazed_terracotta", - "id" : 229 - }, - { - "name" : "minecraft:dark_oak_boat", - "id" : 380 - }, - { - "name" : "minecraft:dark_oak_button", - "id" : -142 - }, - { - "name" : "minecraft:dark_oak_chest_boat", - "id" : 643 - }, - { - "name" : "minecraft:dark_oak_door", - "id" : 557 - }, - { - "name" : "minecraft:dark_oak_fence_gate", - "id" : 186 - }, - { - "name" : "minecraft:dark_oak_pressure_plate", - "id" : -152 - }, - { - "name" : "minecraft:dark_oak_sign", - "id" : 580 - }, - { - "name" : "minecraft:dark_oak_stairs", - "id" : 164 - }, - { - "name" : "minecraft:dark_oak_trapdoor", - "id" : -147 - }, - { - "name" : "minecraft:dark_prismarine_stairs", - "id" : -3 - }, - { - "name" : "minecraft:darkoak_standing_sign", - "id" : -192 - }, - { - "name" : "minecraft:darkoak_wall_sign", - "id" : -193 - }, - { - "name" : "minecraft:daylight_detector", - "id" : 151 - }, - { - "name" : "minecraft:daylight_detector_inverted", - "id" : 178 - }, - { - "name" : "minecraft:deadbush", - "id" : 32 - }, - { - "name" : "minecraft:deepslate", - "id" : -378 - }, - { - "name" : "minecraft:deepslate_brick_double_slab", - "id" : -399 - }, - { - "name" : "minecraft:deepslate_brick_slab", - "id" : -392 - }, - { - "name" : "minecraft:deepslate_brick_stairs", - "id" : -393 - }, - { - "name" : "minecraft:deepslate_brick_wall", - "id" : -394 - }, - { - "name" : "minecraft:deepslate_bricks", - "id" : -391 - }, - { - "name" : "minecraft:deepslate_coal_ore", - "id" : -406 - }, - { - "name" : "minecraft:deepslate_copper_ore", - "id" : -408 - }, - { - "name" : "minecraft:deepslate_diamond_ore", - "id" : -405 - }, - { - "name" : "minecraft:deepslate_emerald_ore", - "id" : -407 - }, - { - "name" : "minecraft:deepslate_gold_ore", - "id" : -402 - }, - { - "name" : "minecraft:deepslate_iron_ore", - "id" : -401 - }, - { - "name" : "minecraft:deepslate_lapis_ore", - "id" : -400 - }, - { - "name" : "minecraft:deepslate_redstone_ore", - "id" : -403 - }, - { - "name" : "minecraft:deepslate_tile_double_slab", - "id" : -398 - }, - { - "name" : "minecraft:deepslate_tile_slab", - "id" : -388 - }, - { - "name" : "minecraft:deepslate_tile_stairs", - "id" : -389 - }, - { - "name" : "minecraft:deepslate_tile_wall", - "id" : -390 - }, - { - "name" : "minecraft:deepslate_tiles", - "id" : -387 - }, - { - "name" : "minecraft:deny", - "id" : 211 - }, - { - "name" : "minecraft:detector_rail", - "id" : 28 - }, - { - "name" : "minecraft:diamond", - "id" : 304 - }, - { - "name" : "minecraft:diamond_axe", - "id" : 319 - }, - { - "name" : "minecraft:diamond_block", - "id" : 57 - }, - { - "name" : "minecraft:diamond_boots", - "id" : 350 - }, - { - "name" : "minecraft:diamond_chestplate", - "id" : 348 - }, - { - "name" : "minecraft:diamond_helmet", - "id" : 347 - }, - { - "name" : "minecraft:diamond_hoe", - "id" : 332 - }, - { - "name" : "minecraft:diamond_horse_armor", - "id" : 533 - }, - { - "name" : "minecraft:diamond_leggings", - "id" : 349 - }, - { - "name" : "minecraft:diamond_ore", - "id" : 56 - }, - { - "name" : "minecraft:diamond_pickaxe", - "id" : 318 - }, - { - "name" : "minecraft:diamond_shovel", - "id" : 317 - }, - { - "name" : "minecraft:diamond_sword", - "id" : 316 - }, - { - "name" : "minecraft:diorite_stairs", - "id" : -170 - }, - { - "name" : "minecraft:dirt", - "id" : 3 - }, - { - "name" : "minecraft:dirt_with_roots", - "id" : -318 - }, - { - "name" : "minecraft:disc_fragment_5", - "id" : 637 - }, - { - "name" : "minecraft:dispenser", - "id" : 23 - }, - { - "name" : "minecraft:dolphin_spawn_egg", - "id" : 484 - }, - { - "name" : "minecraft:donkey_spawn_egg", - "id" : 465 - }, - { - "name" : "minecraft:double_cut_copper_slab", - "id" : -368 - }, - { - "name" : "minecraft:double_plant", - "id" : 175 - }, - { - "name" : "minecraft:double_stone_block_slab", - "id" : 43 - }, - { - "name" : "minecraft:double_stone_block_slab2", - "id" : 181 - }, - { - "name" : "minecraft:double_stone_block_slab3", - "id" : -167 - }, - { - "name" : "minecraft:double_stone_block_slab4", - "id" : -168 - }, - { - "name" : "minecraft:double_wooden_slab", - "id" : 157 - }, - { - "name" : "minecraft:dragon_breath", - "id" : 560 - }, - { - "name" : "minecraft:dragon_egg", - "id" : 122 - }, - { - "name" : "minecraft:dried_kelp", - "id" : 270 - }, - { - "name" : "minecraft:dried_kelp_block", - "id" : -139 - }, - { - "name" : "minecraft:dripstone_block", - "id" : -317 - }, - { - "name" : "minecraft:dropper", - "id" : 125 - }, - { - "name" : "minecraft:drowned_spawn_egg", - "id" : 483 - }, - { - "name" : "minecraft:dye", - "id" : 650 - }, - { - "name" : "minecraft:echo_shard", - "id" : 647 - }, - { - "name" : "minecraft:egg", - "id" : 390 - }, - { - "name" : "minecraft:elder_guardian_spawn_egg", - "id" : 471 - }, - { - "name" : "minecraft:element_0", - "id" : 36 - }, - { - "name" : "minecraft:element_1", - "id" : -12 - }, - { - "name" : "minecraft:element_10", - "id" : -21 - }, - { - "name" : "minecraft:element_100", - "id" : -111 - }, - { - "name" : "minecraft:element_101", - "id" : -112 - }, - { - "name" : "minecraft:element_102", - "id" : -113 - }, - { - "name" : "minecraft:element_103", - "id" : -114 - }, - { - "name" : "minecraft:element_104", - "id" : -115 - }, - { - "name" : "minecraft:element_105", - "id" : -116 - }, - { - "name" : "minecraft:element_106", - "id" : -117 - }, - { - "name" : "minecraft:element_107", - "id" : -118 - }, - { - "name" : "minecraft:element_108", - "id" : -119 - }, - { - "name" : "minecraft:element_109", - "id" : -120 - }, - { - "name" : "minecraft:element_11", - "id" : -22 - }, - { - "name" : "minecraft:element_110", - "id" : -121 - }, - { - "name" : "minecraft:element_111", - "id" : -122 - }, - { - "name" : "minecraft:element_112", - "id" : -123 - }, - { - "name" : "minecraft:element_113", - "id" : -124 - }, - { - "name" : "minecraft:element_114", - "id" : -125 - }, - { - "name" : "minecraft:element_115", - "id" : -126 - }, - { - "name" : "minecraft:element_116", - "id" : -127 - }, - { - "name" : "minecraft:element_117", - "id" : -128 - }, - { - "name" : "minecraft:element_118", - "id" : -129 - }, - { - "name" : "minecraft:element_12", - "id" : -23 - }, - { - "name" : "minecraft:element_13", - "id" : -24 - }, - { - "name" : "minecraft:element_14", - "id" : -25 - }, - { - "name" : "minecraft:element_15", - "id" : -26 - }, - { - "name" : "minecraft:element_16", - "id" : -27 - }, - { - "name" : "minecraft:element_17", - "id" : -28 - }, - { - "name" : "minecraft:element_18", - "id" : -29 - }, - { - "name" : "minecraft:element_19", - "id" : -30 - }, - { - "name" : "minecraft:element_2", - "id" : -13 - }, - { - "name" : "minecraft:element_20", - "id" : -31 - }, - { - "name" : "minecraft:element_21", - "id" : -32 - }, - { - "name" : "minecraft:element_22", - "id" : -33 - }, - { - "name" : "minecraft:element_23", - "id" : -34 - }, - { - "name" : "minecraft:element_24", - "id" : -35 - }, - { - "name" : "minecraft:element_25", - "id" : -36 - }, - { - "name" : "minecraft:element_26", - "id" : -37 - }, - { - "name" : "minecraft:element_27", - "id" : -38 - }, - { - "name" : "minecraft:element_28", - "id" : -39 - }, - { - "name" : "minecraft:element_29", - "id" : -40 - }, - { - "name" : "minecraft:element_3", - "id" : -14 - }, - { - "name" : "minecraft:element_30", - "id" : -41 - }, - { - "name" : "minecraft:element_31", - "id" : -42 - }, - { - "name" : "minecraft:element_32", - "id" : -43 - }, - { - "name" : "minecraft:element_33", - "id" : -44 - }, - { - "name" : "minecraft:element_34", - "id" : -45 - }, - { - "name" : "minecraft:element_35", - "id" : -46 - }, - { - "name" : "minecraft:element_36", - "id" : -47 - }, - { - "name" : "minecraft:element_37", - "id" : -48 - }, - { - "name" : "minecraft:element_38", - "id" : -49 - }, - { - "name" : "minecraft:element_39", - "id" : -50 - }, - { - "name" : "minecraft:element_4", - "id" : -15 - }, - { - "name" : "minecraft:element_40", - "id" : -51 - }, - { - "name" : "minecraft:element_41", - "id" : -52 - }, - { - "name" : "minecraft:element_42", - "id" : -53 - }, - { - "name" : "minecraft:element_43", - "id" : -54 - }, - { - "name" : "minecraft:element_44", - "id" : -55 - }, - { - "name" : "minecraft:element_45", - "id" : -56 - }, - { - "name" : "minecraft:element_46", - "id" : -57 - }, - { - "name" : "minecraft:element_47", - "id" : -58 - }, - { - "name" : "minecraft:element_48", - "id" : -59 - }, - { - "name" : "minecraft:element_49", - "id" : -60 - }, - { - "name" : "minecraft:element_5", - "id" : -16 - }, - { - "name" : "minecraft:element_50", - "id" : -61 - }, - { - "name" : "minecraft:element_51", - "id" : -62 - }, - { - "name" : "minecraft:element_52", - "id" : -63 - }, - { - "name" : "minecraft:element_53", - "id" : -64 - }, - { - "name" : "minecraft:element_54", - "id" : -65 - }, - { - "name" : "minecraft:element_55", - "id" : -66 - }, - { - "name" : "minecraft:element_56", - "id" : -67 - }, - { - "name" : "minecraft:element_57", - "id" : -68 - }, - { - "name" : "minecraft:element_58", - "id" : -69 - }, - { - "name" : "minecraft:element_59", - "id" : -70 - }, - { - "name" : "minecraft:element_6", - "id" : -17 - }, - { - "name" : "minecraft:element_60", - "id" : -71 - }, - { - "name" : "minecraft:element_61", - "id" : -72 - }, - { - "name" : "minecraft:element_62", - "id" : -73 - }, - { - "name" : "minecraft:element_63", - "id" : -74 - }, - { - "name" : "minecraft:element_64", - "id" : -75 - }, - { - "name" : "minecraft:element_65", - "id" : -76 - }, - { - "name" : "minecraft:element_66", - "id" : -77 - }, - { - "name" : "minecraft:element_67", - "id" : -78 - }, - { - "name" : "minecraft:element_68", - "id" : -79 - }, - { - "name" : "minecraft:element_69", - "id" : -80 - }, - { - "name" : "minecraft:element_7", - "id" : -18 - }, - { - "name" : "minecraft:element_70", - "id" : -81 - }, - { - "name" : "minecraft:element_71", - "id" : -82 - }, - { - "name" : "minecraft:element_72", - "id" : -83 - }, - { - "name" : "minecraft:element_73", - "id" : -84 - }, - { - "name" : "minecraft:element_74", - "id" : -85 - }, - { - "name" : "minecraft:element_75", - "id" : -86 - }, - { - "name" : "minecraft:element_76", - "id" : -87 - }, - { - "name" : "minecraft:element_77", - "id" : -88 - }, - { - "name" : "minecraft:element_78", - "id" : -89 - }, - { - "name" : "minecraft:element_79", - "id" : -90 - }, - { - "name" : "minecraft:element_8", - "id" : -19 - }, - { - "name" : "minecraft:element_80", - "id" : -91 - }, - { - "name" : "minecraft:element_81", - "id" : -92 - }, - { - "name" : "minecraft:element_82", - "id" : -93 - }, - { - "name" : "minecraft:element_83", - "id" : -94 - }, - { - "name" : "minecraft:element_84", - "id" : -95 - }, - { - "name" : "minecraft:element_85", - "id" : -96 - }, - { - "name" : "minecraft:element_86", - "id" : -97 - }, - { - "name" : "minecraft:element_87", - "id" : -98 - }, - { - "name" : "minecraft:element_88", - "id" : -99 - }, - { - "name" : "minecraft:element_89", - "id" : -100 - }, - { - "name" : "minecraft:element_9", - "id" : -20 - }, - { - "name" : "minecraft:element_90", - "id" : -101 - }, - { - "name" : "minecraft:element_91", - "id" : -102 - }, - { - "name" : "minecraft:element_92", - "id" : -103 - }, - { - "name" : "minecraft:element_93", - "id" : -104 - }, - { - "name" : "minecraft:element_94", - "id" : -105 - }, - { - "name" : "minecraft:element_95", - "id" : -106 - }, - { - "name" : "minecraft:element_96", - "id" : -107 - }, - { - "name" : "minecraft:element_97", - "id" : -108 - }, - { - "name" : "minecraft:element_98", - "id" : -109 - }, - { - "name" : "minecraft:element_99", - "id" : -110 - }, - { - "name" : "minecraft:elytra", - "id" : 564 - }, - { - "name" : "minecraft:emerald", - "id" : 512 - }, - { - "name" : "minecraft:emerald_block", - "id" : 133 - }, - { - "name" : "minecraft:emerald_ore", - "id" : 129 - }, - { - "name" : "minecraft:empty_map", - "id" : 515 - }, - { - "name" : "minecraft:enchanted_book", - "id" : 521 - }, - { - "name" : "minecraft:enchanted_golden_apple", - "id" : 259 - }, - { - "name" : "minecraft:enchanting_table", - "id" : 116 - }, - { - "name" : "minecraft:end_brick_stairs", - "id" : -178 - }, - { - "name" : "minecraft:end_bricks", - "id" : 206 - }, - { - "name" : "minecraft:end_crystal", - "id" : 653 - }, - { - "name" : "minecraft:end_gateway", - "id" : 209 - }, - { - "name" : "minecraft:end_portal", - "id" : 119 - }, - { - "name" : "minecraft:end_portal_frame", - "id" : 120 - }, - { - "name" : "minecraft:end_rod", - "id" : 208 - }, - { - "name" : "minecraft:end_stone", - "id" : 121 - }, - { - "name" : "minecraft:ender_chest", - "id" : 130 - }, - { - "name" : "minecraft:ender_eye", - "id" : 433 - }, - { - "name" : "minecraft:ender_pearl", - "id" : 422 - }, - { - "name" : "minecraft:enderman_spawn_egg", - "id" : 442 - }, - { - "name" : "minecraft:endermite_spawn_egg", - "id" : 460 - }, - { - "name" : "minecraft:evoker_spawn_egg", - "id" : 475 - }, - { - "name" : "minecraft:experience_bottle", - "id" : 508 - }, - { - "name" : "minecraft:exposed_copper", - "id" : -341 - }, - { - "name" : "minecraft:exposed_cut_copper", - "id" : -348 - }, - { - "name" : "minecraft:exposed_cut_copper_slab", - "id" : -362 - }, - { - "name" : "minecraft:exposed_cut_copper_stairs", - "id" : -355 - }, - { - "name" : "minecraft:exposed_double_cut_copper_slab", - "id" : -369 - }, - { - "name" : "minecraft:farmland", - "id" : 60 - }, - { - "name" : "minecraft:feather", - "id" : 327 - }, - { - "name" : "minecraft:fence", - "id" : 85 - }, - { - "name" : "minecraft:fence_gate", - "id" : 107 - }, - { - "name" : "minecraft:fermented_spider_eye", - "id" : 428 - }, - { - "name" : "minecraft:field_masoned_banner_pattern", - "id" : 585 - }, - { - "name" : "minecraft:filled_map", - "id" : 420 - }, - { - "name" : "minecraft:fire", - "id" : 51 - }, - { - "name" : "minecraft:fire_charge", - "id" : 509 - }, - { - "name" : "minecraft:firework_rocket", - "id" : 519 - }, - { - "name" : "minecraft:firework_star", - "id" : 520 - }, - { - "name" : "minecraft:fishing_rod", - "id" : 392 - }, - { - "name" : "minecraft:fletching_table", - "id" : -201 - }, - { - "name" : "minecraft:flint", - "id" : 356 - }, - { - "name" : "minecraft:flint_and_steel", - "id" : 299 - }, - { - "name" : "minecraft:flower_banner_pattern", - "id" : 581 - }, - { - "name" : "minecraft:flower_pot", - "id" : 514 - }, - { - "name" : "minecraft:flowering_azalea", - "id" : -338 - }, - { - "name" : "minecraft:flowing_lava", - "id" : 10 - }, - { - "name" : "minecraft:flowing_water", - "id" : 8 - }, - { - "name" : "minecraft:fox_spawn_egg", - "id" : 490 - }, - { - "name" : "minecraft:frame", - "id" : 513 - }, - { - "name" : "minecraft:frog_spawn", - "id" : -468 - }, - { - "name" : "minecraft:frog_spawn_egg", - "id" : 628 - }, - { - "name" : "minecraft:frosted_ice", - "id" : 207 - }, - { - "name" : "minecraft:furnace", - "id" : 61 - }, - { - "name" : "minecraft:ghast_spawn_egg", - "id" : 454 - }, - { - "name" : "minecraft:ghast_tear", - "id" : 424 - }, - { - "name" : "minecraft:gilded_blackstone", - "id" : -281 - }, - { - "name" : "minecraft:glass", - "id" : 20 - }, - { - "name" : "minecraft:glass_bottle", - "id" : 427 - }, - { - "name" : "minecraft:glass_pane", - "id" : 102 - }, - { - "name" : "minecraft:glistering_melon_slice", - "id" : 434 - }, - { - "name" : "minecraft:globe_banner_pattern", - "id" : 588 - }, - { - "name" : "minecraft:glow_berries", - "id" : 654 - }, - { - "name" : "minecraft:glow_frame", - "id" : 623 - }, - { - "name" : "minecraft:glow_ink_sac", - "id" : 503 - }, - { - "name" : "minecraft:glow_lichen", - "id" : -411 - }, - { - "name" : "minecraft:glow_squid_spawn_egg", - "id" : 502 - }, - { - "name" : "minecraft:glow_stick", - "id" : 601 - }, - { - "name" : "minecraft:glowingobsidian", - "id" : 246 - }, - { - "name" : "minecraft:glowstone", - "id" : 89 - }, - { - "name" : "minecraft:glowstone_dust", - "id" : 394 - }, - { - "name" : "minecraft:goat_horn", - "id" : 627 - }, - { - "name" : "minecraft:goat_spawn_egg", - "id" : 501 - }, - { - "name" : "minecraft:gold_block", - "id" : 41 - }, - { - "name" : "minecraft:gold_ingot", - "id" : 306 - }, - { - "name" : "minecraft:gold_nugget", - "id" : 425 - }, - { - "name" : "minecraft:gold_ore", - "id" : 14 - }, - { - "name" : "minecraft:golden_apple", - "id" : 258 - }, - { - "name" : "minecraft:golden_axe", - "id" : 325 - }, - { - "name" : "minecraft:golden_boots", - "id" : 354 - }, - { - "name" : "minecraft:golden_carrot", - "id" : 283 - }, - { - "name" : "minecraft:golden_chestplate", - "id" : 352 - }, - { - "name" : "minecraft:golden_helmet", - "id" : 351 - }, - { - "name" : "minecraft:golden_hoe", - "id" : 333 - }, - { - "name" : "minecraft:golden_horse_armor", - "id" : 532 - }, - { - "name" : "minecraft:golden_leggings", - "id" : 353 - }, - { - "name" : "minecraft:golden_pickaxe", - "id" : 324 - }, - { - "name" : "minecraft:golden_rail", - "id" : 27 - }, - { - "name" : "minecraft:golden_shovel", - "id" : 323 - }, - { - "name" : "minecraft:golden_sword", - "id" : 322 - }, - { - "name" : "minecraft:granite_stairs", - "id" : -169 - }, - { - "name" : "minecraft:grass", - "id" : 2 - }, - { - "name" : "minecraft:grass_path", - "id" : 198 - }, - { - "name" : "minecraft:gravel", - "id" : 13 - }, - { - "name" : "minecraft:gray_candle", - "id" : -420 - }, - { - "name" : "minecraft:gray_candle_cake", - "id" : -437 - }, - { - "name" : "minecraft:gray_dye", - "id" : 403 - }, - { - "name" : "minecraft:gray_glazed_terracotta", - "id" : 227 - }, - { - "name" : "minecraft:green_candle", - "id" : -426 - }, - { - "name" : "minecraft:green_candle_cake", - "id" : -443 - }, - { - "name" : "minecraft:green_dye", - "id" : 397 - }, - { - "name" : "minecraft:green_glazed_terracotta", - "id" : 233 - }, - { - "name" : "minecraft:grindstone", - "id" : -195 - }, - { - "name" : "minecraft:guardian_spawn_egg", - "id" : 461 - }, - { - "name" : "minecraft:gunpowder", - "id" : 328 - }, - { - "name" : "minecraft:hanging_roots", - "id" : -319 - }, - { - "name" : "minecraft:hard_glass", - "id" : 253 - }, - { - "name" : "minecraft:hard_glass_pane", - "id" : 190 - }, - { - "name" : "minecraft:hard_stained_glass", - "id" : 254 - }, - { - "name" : "minecraft:hard_stained_glass_pane", - "id" : 191 - }, - { - "name" : "minecraft:hardened_clay", - "id" : 172 - }, - { - "name" : "minecraft:hay_block", - "id" : 170 - }, - { - "name" : "minecraft:heart_of_the_sea", - "id" : 571 - }, - { - "name" : "minecraft:heavy_weighted_pressure_plate", - "id" : 148 - }, - { - "name" : "minecraft:hoglin_spawn_egg", - "id" : 496 - }, - { - "name" : "minecraft:honey_block", - "id" : -220 - }, - { - "name" : "minecraft:honey_bottle", - "id" : 592 - }, - { - "name" : "minecraft:honeycomb", - "id" : 591 - }, - { - "name" : "minecraft:honeycomb_block", - "id" : -221 - }, - { - "name" : "minecraft:hopper", - "id" : 527 - }, - { - "name" : "minecraft:hopper_minecart", - "id" : 526 - }, - { - "name" : "minecraft:horse_spawn_egg", - "id" : 458 - }, - { - "name" : "minecraft:husk_spawn_egg", - "id" : 463 - }, - { - "name" : "minecraft:ice", - "id" : 79 - }, - { - "name" : "minecraft:ice_bomb", - "id" : 595 - }, - { - "name" : "minecraft:infested_deepslate", - "id" : -454 - }, - { - "name" : "minecraft:info_update", - "id" : 248 - }, - { - "name" : "minecraft:info_update2", - "id" : 249 - }, - { - "name" : "minecraft:ink_sac", - "id" : 413 - }, - { - "name" : "minecraft:invisible_bedrock", - "id" : 95 - }, - { - "name" : "minecraft:iron_axe", - "id" : 298 - }, - { - "name" : "minecraft:iron_bars", - "id" : 101 - }, - { - "name" : "minecraft:iron_block", - "id" : 42 - }, - { - "name" : "minecraft:iron_boots", - "id" : 346 - }, - { - "name" : "minecraft:iron_chestplate", - "id" : 344 - }, - { - "name" : "minecraft:iron_door", - "id" : 372 - }, - { - "name" : "minecraft:iron_helmet", - "id" : 343 - }, - { - "name" : "minecraft:iron_hoe", - "id" : 331 - }, - { - "name" : "minecraft:iron_horse_armor", - "id" : 531 - }, - { - "name" : "minecraft:iron_ingot", - "id" : 305 - }, - { - "name" : "minecraft:iron_leggings", - "id" : 345 - }, - { - "name" : "minecraft:iron_nugget", - "id" : 569 - }, - { - "name" : "minecraft:iron_ore", - "id" : 15 - }, - { - "name" : "minecraft:iron_pickaxe", - "id" : 297 - }, - { - "name" : "minecraft:iron_shovel", - "id" : 296 - }, - { - "name" : "minecraft:iron_sword", - "id" : 307 - }, - { - "name" : "minecraft:iron_trapdoor", - "id" : 167 - }, - { - "name" : "minecraft:item.acacia_door", - "id" : 196 - }, - { - "name" : "minecraft:item.bed", - "id" : 26 - }, - { - "name" : "minecraft:item.beetroot", - "id" : 244 - }, - { - "name" : "minecraft:item.birch_door", - "id" : 194 - }, - { - "name" : "minecraft:item.brewing_stand", - "id" : 117 - }, - { - "name" : "minecraft:item.cake", - "id" : 92 - }, - { - "name" : "minecraft:item.camera", - "id" : 242 - }, - { - "name" : "minecraft:item.campfire", - "id" : -209 - }, - { - "name" : "minecraft:item.cauldron", - "id" : 118 - }, - { - "name" : "minecraft:item.chain", - "id" : -286 - }, - { - "name" : "minecraft:item.crimson_door", - "id" : -244 - }, - { - "name" : "minecraft:item.dark_oak_door", - "id" : 197 - }, - { - "name" : "minecraft:item.flower_pot", - "id" : 140 - }, - { - "name" : "minecraft:item.frame", - "id" : 199 - }, - { - "name" : "minecraft:item.glow_frame", - "id" : -339 - }, - { - "name" : "minecraft:item.hopper", - "id" : 154 - }, - { - "name" : "minecraft:item.iron_door", - "id" : 71 - }, - { - "name" : "minecraft:item.jungle_door", - "id" : 195 - }, - { - "name" : "minecraft:item.kelp", - "id" : -138 - }, - { - "name" : "minecraft:item.mangrove_door", - "id" : -493 - }, - { - "name" : "minecraft:item.nether_sprouts", - "id" : -238 - }, - { - "name" : "minecraft:item.nether_wart", - "id" : 115 - }, - { - "name" : "minecraft:item.reeds", - "id" : 83 - }, - { - "name" : "minecraft:item.skull", - "id" : 144 - }, - { - "name" : "minecraft:item.soul_campfire", - "id" : -290 - }, - { - "name" : "minecraft:item.spruce_door", - "id" : 193 - }, - { - "name" : "minecraft:item.warped_door", - "id" : -245 - }, - { - "name" : "minecraft:item.wheat", - "id" : 59 - }, - { - "name" : "minecraft:item.wooden_door", - "id" : 64 - }, - { - "name" : "minecraft:jigsaw", - "id" : -211 - }, - { - "name" : "minecraft:jukebox", - "id" : 84 - }, - { - "name" : "minecraft:jungle_boat", - "id" : 377 - }, - { - "name" : "minecraft:jungle_button", - "id" : -143 - }, - { - "name" : "minecraft:jungle_chest_boat", - "id" : 640 - }, - { - "name" : "minecraft:jungle_door", - "id" : 555 - }, - { - "name" : "minecraft:jungle_fence_gate", - "id" : 185 - }, - { - "name" : "minecraft:jungle_pressure_plate", - "id" : -153 - }, - { - "name" : "minecraft:jungle_sign", - "id" : 578 - }, - { - "name" : "minecraft:jungle_stairs", - "id" : 136 - }, - { - "name" : "minecraft:jungle_standing_sign", - "id" : -188 - }, - { - "name" : "minecraft:jungle_trapdoor", - "id" : -148 - }, - { - "name" : "minecraft:jungle_wall_sign", - "id" : -189 - }, - { - "name" : "minecraft:kelp", - "id" : 382 - }, - { - "name" : "minecraft:ladder", - "id" : 65 - }, - { - "name" : "minecraft:lantern", - "id" : -208 - }, - { - "name" : "minecraft:lapis_block", - "id" : 22 - }, - { - "name" : "minecraft:lapis_lazuli", - "id" : 414 - }, - { - "name" : "minecraft:lapis_ore", - "id" : 21 - }, - { - "name" : "minecraft:large_amethyst_bud", - "id" : -330 - }, - { - "name" : "minecraft:lava", - "id" : 11 - }, - { - "name" : "minecraft:lava_bucket", - "id" : 363 - }, - { - "name" : "minecraft:lava_cauldron", - "id" : -210 - }, - { - "name" : "minecraft:lead", - "id" : 547 - }, - { - "name" : "minecraft:leather", - "id" : 381 - }, - { - "name" : "minecraft:leather_boots", - "id" : 338 - }, - { - "name" : "minecraft:leather_chestplate", - "id" : 336 - }, - { - "name" : "minecraft:leather_helmet", - "id" : 335 - }, - { - "name" : "minecraft:leather_horse_armor", - "id" : 530 - }, - { - "name" : "minecraft:leather_leggings", - "id" : 337 - }, - { - "name" : "minecraft:leaves", - "id" : 18 - }, - { - "name" : "minecraft:leaves2", - "id" : 161 - }, - { - "name" : "minecraft:lectern", - "id" : -194 - }, - { - "name" : "minecraft:lever", - "id" : 69 - }, - { - "name" : "minecraft:light_block", - "id" : -215 - }, - { - "name" : "minecraft:light_blue_candle", - "id" : -416 - }, - { - "name" : "minecraft:light_blue_candle_cake", - "id" : -433 - }, - { - "name" : "minecraft:light_blue_dye", - "id" : 407 - }, - { - "name" : "minecraft:light_blue_glazed_terracotta", - "id" : 223 - }, - { - "name" : "minecraft:light_gray_candle", - "id" : -421 - }, - { - "name" : "minecraft:light_gray_candle_cake", - "id" : -438 - }, - { - "name" : "minecraft:light_gray_dye", - "id" : 402 - }, - { - "name" : "minecraft:light_weighted_pressure_plate", - "id" : 147 - }, - { - "name" : "minecraft:lightning_rod", - "id" : -312 - }, - { - "name" : "minecraft:lime_candle", - "id" : -418 - }, - { - "name" : "minecraft:lime_candle_cake", - "id" : -435 - }, - { - "name" : "minecraft:lime_dye", - "id" : 405 - }, - { - "name" : "minecraft:lime_glazed_terracotta", - "id" : 225 - }, - { - "name" : "minecraft:lingering_potion", - "id" : 562 - }, - { - "name" : "minecraft:lit_blast_furnace", - "id" : -214 - }, - { - "name" : "minecraft:lit_deepslate_redstone_ore", - "id" : -404 - }, - { - "name" : "minecraft:lit_furnace", - "id" : 62 - }, - { - "name" : "minecraft:lit_pumpkin", - "id" : 91 - }, - { - "name" : "minecraft:lit_redstone_lamp", - "id" : 124 - }, - { - "name" : "minecraft:lit_redstone_ore", - "id" : 74 - }, - { - "name" : "minecraft:lit_smoker", - "id" : -199 - }, - { - "name" : "minecraft:llama_spawn_egg", - "id" : 473 - }, - { - "name" : "minecraft:lodestone", - "id" : -222 - }, - { - "name" : "minecraft:lodestone_compass", - "id" : 602 - }, - { - "name" : "minecraft:log", - "id" : 17 - }, - { - "name" : "minecraft:log2", - "id" : 162 - }, - { - "name" : "minecraft:loom", - "id" : -204 - }, - { - "name" : "minecraft:magenta_candle", - "id" : -415 - }, - { - "name" : "minecraft:magenta_candle_cake", - "id" : -432 - }, - { - "name" : "minecraft:magenta_dye", - "id" : 408 - }, - { - "name" : "minecraft:magenta_glazed_terracotta", - "id" : 222 - }, - { - "name" : "minecraft:magma", - "id" : 213 - }, - { - "name" : "minecraft:magma_cream", - "id" : 430 - }, - { - "name" : "minecraft:magma_cube_spawn_egg", - "id" : 455 - }, - { - "name" : "minecraft:mangrove_boat", - "id" : 635 - }, - { - "name" : "minecraft:mangrove_button", - "id" : -487 - }, - { - "name" : "minecraft:mangrove_chest_boat", - "id" : 644 - }, - { - "name" : "minecraft:mangrove_door", - "id" : 633 - }, - { - "name" : "minecraft:mangrove_double_slab", - "id" : -499 - }, - { - "name" : "minecraft:mangrove_fence", - "id" : -491 - }, - { - "name" : "minecraft:mangrove_fence_gate", - "id" : -492 - }, - { - "name" : "minecraft:mangrove_leaves", - "id" : -472 - }, - { - "name" : "minecraft:mangrove_log", - "id" : -484 - }, - { - "name" : "minecraft:mangrove_planks", - "id" : -486 - }, - { - "name" : "minecraft:mangrove_pressure_plate", - "id" : -490 - }, - { - "name" : "minecraft:mangrove_propagule", - "id" : -474 - }, - { - "name" : "minecraft:mangrove_roots", - "id" : -482 - }, - { - "name" : "minecraft:mangrove_sign", - "id" : 634 - }, - { - "name" : "minecraft:mangrove_slab", - "id" : -489 - }, - { - "name" : "minecraft:mangrove_stairs", - "id" : -488 - }, - { - "name" : "minecraft:mangrove_standing_sign", - "id" : -494 - }, - { - "name" : "minecraft:mangrove_trapdoor", - "id" : -496 - }, - { - "name" : "minecraft:mangrove_wall_sign", - "id" : -495 - }, - { - "name" : "minecraft:mangrove_wood", - "id" : -497 - }, - { - "name" : "minecraft:medicine", - "id" : 599 - }, - { - "name" : "minecraft:medium_amethyst_bud", - "id" : -331 - }, - { - "name" : "minecraft:melon_block", - "id" : 103 - }, - { - "name" : "minecraft:melon_seeds", - "id" : 293 - }, - { - "name" : "minecraft:melon_slice", - "id" : 272 - }, - { - "name" : "minecraft:melon_stem", - "id" : 105 - }, - { - "name" : "minecraft:milk_bucket", - "id" : 361 - }, - { - "name" : "minecraft:minecart", - "id" : 370 - }, - { - "name" : "minecraft:mob_spawner", - "id" : 52 - }, - { - "name" : "minecraft:mojang_banner_pattern", - "id" : 584 - }, - { - "name" : "minecraft:monster_egg", - "id" : 97 - }, - { - "name" : "minecraft:mooshroom_spawn_egg", - "id" : 440 - }, - { - "name" : "minecraft:moss_block", - "id" : -320 - }, - { - "name" : "minecraft:moss_carpet", - "id" : -335 - }, - { - "name" : "minecraft:mossy_cobblestone", - "id" : 48 - }, - { - "name" : "minecraft:mossy_cobblestone_stairs", - "id" : -179 - }, - { - "name" : "minecraft:mossy_stone_brick_stairs", - "id" : -175 - }, - { - "name" : "minecraft:moving_block", - "id" : 250 - }, - { - "name" : "minecraft:mud", - "id" : -473 - }, - { - "name" : "minecraft:mud_brick_double_slab", - "id" : -479 - }, - { - "name" : "minecraft:mud_brick_slab", - "id" : -478 - }, - { - "name" : "minecraft:mud_brick_stairs", - "id" : -480 - }, - { - "name" : "minecraft:mud_brick_wall", - "id" : -481 - }, - { - "name" : "minecraft:mud_bricks", - "id" : -475 - }, - { - "name" : "minecraft:muddy_mangrove_roots", - "id" : -483 - }, - { - "name" : "minecraft:mule_spawn_egg", - "id" : 466 - }, - { - "name" : "minecraft:mushroom_stew", - "id" : 260 - }, - { - "name" : "minecraft:music_disc_11", - "id" : 544 - }, - { - "name" : "minecraft:music_disc_13", - "id" : 534 - }, - { - "name" : "minecraft:music_disc_5", - "id" : 636 - }, - { - "name" : "minecraft:music_disc_blocks", - "id" : 536 - }, - { - "name" : "minecraft:music_disc_cat", - "id" : 535 - }, - { - "name" : "minecraft:music_disc_chirp", - "id" : 537 - }, - { - "name" : "minecraft:music_disc_far", - "id" : 538 - }, - { - "name" : "minecraft:music_disc_mall", - "id" : 539 - }, - { - "name" : "minecraft:music_disc_mellohi", - "id" : 540 - }, - { - "name" : "minecraft:music_disc_otherside", - "id" : 626 - }, - { - "name" : "minecraft:music_disc_pigstep", - "id" : 620 - }, - { - "name" : "minecraft:music_disc_stal", - "id" : 541 - }, - { - "name" : "minecraft:music_disc_strad", - "id" : 542 - }, - { - "name" : "minecraft:music_disc_wait", - "id" : 545 - }, - { - "name" : "minecraft:music_disc_ward", - "id" : 543 - }, - { - "name" : "minecraft:mutton", - "id" : 550 - }, - { - "name" : "minecraft:mycelium", - "id" : 110 - }, - { - "name" : "minecraft:name_tag", - "id" : 548 - }, - { - "name" : "minecraft:nautilus_shell", - "id" : 570 - }, - { - "name" : "minecraft:nether_brick", - "id" : 112 - }, - { - "name" : "minecraft:nether_brick_fence", - "id" : 113 - }, - { - "name" : "minecraft:nether_brick_stairs", - "id" : 114 - }, - { - "name" : "minecraft:nether_gold_ore", - "id" : -288 - }, - { - "name" : "minecraft:nether_sprouts", - "id" : 621 - }, - { - "name" : "minecraft:nether_star", - "id" : 518 - }, - { - "name" : "minecraft:nether_wart", - "id" : 294 - }, - { - "name" : "minecraft:nether_wart_block", - "id" : 214 - }, - { - "name" : "minecraft:netherbrick", - "id" : 523 - }, - { - "name" : "minecraft:netherite_axe", - "id" : 607 - }, - { - "name" : "minecraft:netherite_block", - "id" : -270 - }, - { - "name" : "minecraft:netherite_boots", - "id" : 612 - }, - { - "name" : "minecraft:netherite_chestplate", - "id" : 610 - }, - { - "name" : "minecraft:netherite_helmet", - "id" : 609 - }, - { - "name" : "minecraft:netherite_hoe", - "id" : 608 - }, - { - "name" : "minecraft:netherite_ingot", - "id" : 603 - }, - { - "name" : "minecraft:netherite_leggings", - "id" : 611 - }, - { - "name" : "minecraft:netherite_pickaxe", - "id" : 606 - }, - { - "name" : "minecraft:netherite_scrap", - "id" : 613 - }, - { - "name" : "minecraft:netherite_shovel", - "id" : 605 - }, - { - "name" : "minecraft:netherite_sword", - "id" : 604 - }, - { - "name" : "minecraft:netherrack", - "id" : 87 - }, - { - "name" : "minecraft:netherreactor", - "id" : 247 - }, - { - "name" : "minecraft:normal_stone_stairs", - "id" : -180 - }, - { - "name" : "minecraft:noteblock", - "id" : 25 - }, - { - "name" : "minecraft:npc_spawn_egg", - "id" : 470 - }, - { - "name" : "minecraft:oak_boat", - "id" : 375 - }, - { - "name" : "minecraft:oak_chest_boat", - "id" : 638 - }, - { - "name" : "minecraft:oak_sign", - "id" : 358 - }, - { - "name" : "minecraft:oak_stairs", - "id" : 53 - }, - { - "name" : "minecraft:observer", - "id" : 251 - }, - { - "name" : "minecraft:obsidian", - "id" : 49 - }, - { - "name" : "minecraft:ocelot_spawn_egg", - "id" : 451 - }, - { - "name" : "minecraft:ochre_froglight", - "id" : -471 - }, - { - "name" : "minecraft:orange_candle", - "id" : -414 - }, - { - "name" : "minecraft:orange_candle_cake", - "id" : -431 - }, - { - "name" : "minecraft:orange_dye", - "id" : 409 - }, - { - "name" : "minecraft:orange_glazed_terracotta", - "id" : 221 - }, - { - "name" : "minecraft:oxidized_copper", - "id" : -343 - }, - { - "name" : "minecraft:oxidized_cut_copper", - "id" : -350 - }, - { - "name" : "minecraft:oxidized_cut_copper_slab", - "id" : -364 - }, - { - "name" : "minecraft:oxidized_cut_copper_stairs", - "id" : -357 - }, - { - "name" : "minecraft:oxidized_double_cut_copper_slab", - "id" : -371 - }, - { - "name" : "minecraft:packed_ice", - "id" : 174 - }, - { - "name" : "minecraft:packed_mud", - "id" : -477 - }, - { - "name" : "minecraft:painting", - "id" : 357 - }, - { - "name" : "minecraft:panda_spawn_egg", - "id" : 489 - }, - { - "name" : "minecraft:paper", - "id" : 386 - }, - { - "name" : "minecraft:parrot_spawn_egg", - "id" : 478 - }, - { - "name" : "minecraft:pearlescent_froglight", - "id" : -469 - }, - { - "name" : "minecraft:phantom_membrane", - "id" : 574 - }, - { - "name" : "minecraft:phantom_spawn_egg", - "id" : 486 - }, - { - "name" : "minecraft:pig_spawn_egg", - "id" : 437 - }, - { - "name" : "minecraft:piglin_banner_pattern", - "id" : 587 - }, - { - "name" : "minecraft:piglin_brute_spawn_egg", - "id" : 499 - }, - { - "name" : "minecraft:piglin_spawn_egg", - "id" : 497 - }, - { - "name" : "minecraft:pillager_spawn_egg", - "id" : 491 - }, - { - "name" : "minecraft:pink_candle", - "id" : -419 - }, - { - "name" : "minecraft:pink_candle_cake", - "id" : -436 - }, - { - "name" : "minecraft:pink_dye", - "id" : 404 - }, - { - "name" : "minecraft:pink_glazed_terracotta", - "id" : 226 - }, - { - "name" : "minecraft:piston", - "id" : 33 - }, - { - "name" : "minecraft:piston_arm_collision", - "id" : 34 - }, - { - "name" : "minecraft:planks", - "id" : 5 - }, - { - "name" : "minecraft:podzol", - "id" : 243 - }, - { - "name" : "minecraft:pointed_dripstone", - "id" : -308 - }, - { - "name" : "minecraft:poisonous_potato", - "id" : 282 - }, - { - "name" : "minecraft:polar_bear_spawn_egg", - "id" : 472 - }, - { - "name" : "minecraft:polished_andesite_stairs", - "id" : -174 - }, - { - "name" : "minecraft:polished_basalt", - "id" : -235 - }, - { - "name" : "minecraft:polished_blackstone", - "id" : -291 - }, - { - "name" : "minecraft:polished_blackstone_brick_double_slab", - "id" : -285 - }, - { - "name" : "minecraft:polished_blackstone_brick_slab", - "id" : -284 - }, - { - "name" : "minecraft:polished_blackstone_brick_stairs", - "id" : -275 - }, - { - "name" : "minecraft:polished_blackstone_brick_wall", - "id" : -278 - }, - { - "name" : "minecraft:polished_blackstone_bricks", - "id" : -274 - }, - { - "name" : "minecraft:polished_blackstone_button", - "id" : -296 - }, - { - "name" : "minecraft:polished_blackstone_double_slab", - "id" : -294 - }, - { - "name" : "minecraft:polished_blackstone_pressure_plate", - "id" : -295 - }, - { - "name" : "minecraft:polished_blackstone_slab", - "id" : -293 - }, - { - "name" : "minecraft:polished_blackstone_stairs", - "id" : -292 - }, - { - "name" : "minecraft:polished_blackstone_wall", - "id" : -297 - }, - { - "name" : "minecraft:polished_deepslate", - "id" : -383 - }, - { - "name" : "minecraft:polished_deepslate_double_slab", - "id" : -397 - }, - { - "name" : "minecraft:polished_deepslate_slab", - "id" : -384 - }, - { - "name" : "minecraft:polished_deepslate_stairs", - "id" : -385 - }, - { - "name" : "minecraft:polished_deepslate_wall", - "id" : -386 - }, - { - "name" : "minecraft:polished_diorite_stairs", - "id" : -173 - }, - { - "name" : "minecraft:polished_granite_stairs", - "id" : -172 - }, - { - "name" : "minecraft:popped_chorus_fruit", - "id" : 559 - }, - { - "name" : "minecraft:porkchop", - "id" : 262 - }, - { - "name" : "minecraft:portal", - "id" : 90 - }, - { - "name" : "minecraft:potato", - "id" : 280 - }, - { - "name" : "minecraft:potatoes", - "id" : 142 - }, - { - "name" : "minecraft:potion", - "id" : 426 - }, - { - "name" : "minecraft:powder_snow", - "id" : -306 - }, - { - "name" : "minecraft:powder_snow_bucket", - "id" : 368 - }, - { - "name" : "minecraft:powered_comparator", - "id" : 150 - }, - { - "name" : "minecraft:powered_repeater", - "id" : 94 - }, - { - "name" : "minecraft:prismarine", - "id" : 168 - }, - { - "name" : "minecraft:prismarine_bricks_stairs", - "id" : -4 - }, - { - "name" : "minecraft:prismarine_crystals", - "id" : 549 - }, - { - "name" : "minecraft:prismarine_shard", - "id" : 565 - }, - { - "name" : "minecraft:prismarine_stairs", - "id" : -2 - }, - { - "name" : "minecraft:pufferfish", - "id" : 267 - }, - { - "name" : "minecraft:pufferfish_bucket", - "id" : 367 - }, - { - "name" : "minecraft:pufferfish_spawn_egg", - "id" : 481 - }, - { - "name" : "minecraft:pumpkin", - "id" : 86 - }, - { - "name" : "minecraft:pumpkin_pie", - "id" : 284 - }, - { - "name" : "minecraft:pumpkin_seeds", - "id" : 292 - }, - { - "name" : "minecraft:pumpkin_stem", - "id" : 104 - }, - { - "name" : "minecraft:purple_candle", - "id" : -423 - }, - { - "name" : "minecraft:purple_candle_cake", - "id" : -440 - }, - { - "name" : "minecraft:purple_dye", - "id" : 400 - }, - { - "name" : "minecraft:purple_glazed_terracotta", - "id" : 219 - }, - { - "name" : "minecraft:purpur_block", - "id" : 201 - }, - { - "name" : "minecraft:purpur_stairs", - "id" : 203 - }, - { - "name" : "minecraft:quartz", - "id" : 524 - }, - { - "name" : "minecraft:quartz_block", - "id" : 155 - }, - { - "name" : "minecraft:quartz_bricks", - "id" : -304 - }, - { - "name" : "minecraft:quartz_ore", - "id" : 153 - }, - { - "name" : "minecraft:quartz_stairs", - "id" : 156 - }, - { - "name" : "minecraft:rabbit", - "id" : 288 - }, - { - "name" : "minecraft:rabbit_foot", - "id" : 528 - }, - { - "name" : "minecraft:rabbit_hide", - "id" : 529 - }, - { - "name" : "minecraft:rabbit_spawn_egg", - "id" : 459 - }, - { - "name" : "minecraft:rabbit_stew", - "id" : 290 - }, - { - "name" : "minecraft:rail", - "id" : 66 - }, - { - "name" : "minecraft:rapid_fertilizer", - "id" : 597 - }, - { - "name" : "minecraft:ravager_spawn_egg", - "id" : 493 - }, - { - "name" : "minecraft:raw_copper", - "id" : 507 - }, - { - "name" : "minecraft:raw_copper_block", - "id" : -452 - }, - { - "name" : "minecraft:raw_gold", - "id" : 506 - }, - { - "name" : "minecraft:raw_gold_block", - "id" : -453 - }, - { - "name" : "minecraft:raw_iron", - "id" : 505 - }, - { - "name" : "minecraft:raw_iron_block", - "id" : -451 - }, - { - "name" : "minecraft:recovery_compass", - "id" : 646 - }, - { - "name" : "minecraft:red_candle", - "id" : -427 - }, - { - "name" : "minecraft:red_candle_cake", - "id" : -444 - }, - { - "name" : "minecraft:red_dye", - "id" : 396 - }, - { - "name" : "minecraft:red_flower", - "id" : 38 - }, - { - "name" : "minecraft:red_glazed_terracotta", - "id" : 234 - }, - { - "name" : "minecraft:red_mushroom", - "id" : 40 - }, - { - "name" : "minecraft:red_mushroom_block", - "id" : 100 - }, - { - "name" : "minecraft:red_nether_brick", - "id" : 215 - }, - { - "name" : "minecraft:red_nether_brick_stairs", - "id" : -184 - }, - { - "name" : "minecraft:red_sandstone", - "id" : 179 - }, - { - "name" : "minecraft:red_sandstone_stairs", - "id" : 180 - }, - { - "name" : "minecraft:redstone", - "id" : 373 - }, - { - "name" : "minecraft:redstone_block", - "id" : 152 - }, - { - "name" : "minecraft:redstone_lamp", - "id" : 123 - }, - { - "name" : "minecraft:redstone_ore", - "id" : 73 - }, - { - "name" : "minecraft:redstone_torch", - "id" : 76 - }, - { - "name" : "minecraft:redstone_wire", - "id" : 55 - }, - { - "name" : "minecraft:reinforced_deepslate", - "id" : -466 - }, - { - "name" : "minecraft:repeater", - "id" : 419 - }, - { - "name" : "minecraft:repeating_command_block", - "id" : 188 - }, - { - "name" : "minecraft:reserved6", - "id" : 255 - }, - { - "name" : "minecraft:respawn_anchor", - "id" : -272 - }, - { - "name" : "minecraft:rotten_flesh", - "id" : 277 - }, - { - "name" : "minecraft:saddle", - "id" : 371 - }, - { - "name" : "minecraft:salmon", - "id" : 265 - }, - { - "name" : "minecraft:salmon_bucket", - "id" : 365 - }, - { - "name" : "minecraft:salmon_spawn_egg", - "id" : 482 - }, - { - "name" : "minecraft:sand", - "id" : 12 - }, - { - "name" : "minecraft:sandstone", - "id" : 24 - }, - { - "name" : "minecraft:sandstone_stairs", - "id" : 128 - }, - { - "name" : "minecraft:sapling", - "id" : 6 - }, - { - "name" : "minecraft:scaffolding", - "id" : -165 - }, - { - "name" : "minecraft:sculk", - "id" : -458 - }, - { - "name" : "minecraft:sculk_catalyst", - "id" : -460 - }, - { - "name" : "minecraft:sculk_sensor", - "id" : -307 - }, - { - "name" : "minecraft:sculk_shrieker", - "id" : -461 - }, - { - "name" : "minecraft:sculk_vein", - "id" : -459 - }, - { - "name" : "minecraft:scute", - "id" : 572 - }, - { - "name" : "minecraft:sea_lantern", - "id" : 169 - }, - { - "name" : "minecraft:sea_pickle", - "id" : -156 - }, - { - "name" : "minecraft:seagrass", - "id" : -130 - }, - { - "name" : "minecraft:shears", - "id" : 421 - }, - { - "name" : "minecraft:sheep_spawn_egg", - "id" : 438 - }, - { - "name" : "minecraft:shield", - "id" : 355 - }, - { - "name" : "minecraft:shroomlight", - "id" : -230 - }, - { - "name" : "minecraft:shulker_box", - "id" : 218 - }, - { - "name" : "minecraft:shulker_shell", - "id" : 566 - }, - { - "name" : "minecraft:shulker_spawn_egg", - "id" : 469 - }, - { - "name" : "minecraft:silver_glazed_terracotta", - "id" : 228 - }, - { - "name" : "minecraft:silverfish_spawn_egg", - "id" : 443 - }, - { - "name" : "minecraft:skeleton_horse_spawn_egg", - "id" : 467 - }, - { - "name" : "minecraft:skeleton_spawn_egg", - "id" : 444 - }, - { - "name" : "minecraft:skull", - "id" : 516 - }, - { - "name" : "minecraft:skull_banner_pattern", - "id" : 583 - }, - { - "name" : "minecraft:slime", - "id" : 165 - }, - { - "name" : "minecraft:slime_ball", - "id" : 388 - }, - { - "name" : "minecraft:slime_spawn_egg", - "id" : 445 - }, - { - "name" : "minecraft:small_amethyst_bud", - "id" : -332 - }, - { - "name" : "minecraft:small_dripleaf_block", - "id" : -336 - }, - { - "name" : "minecraft:smithing_table", - "id" : -202 - }, - { - "name" : "minecraft:smoker", - "id" : -198 - }, - { - "name" : "minecraft:smooth_basalt", - "id" : -377 - }, - { - "name" : "minecraft:smooth_quartz_stairs", - "id" : -185 - }, - { - "name" : "minecraft:smooth_red_sandstone_stairs", - "id" : -176 - }, - { - "name" : "minecraft:smooth_sandstone_stairs", - "id" : -177 - }, - { - "name" : "minecraft:smooth_stone", - "id" : -183 - }, - { - "name" : "minecraft:snow", - "id" : 80 - }, - { - "name" : "minecraft:snow_layer", - "id" : 78 - }, - { - "name" : "minecraft:snowball", - "id" : 374 - }, - { - "name" : "minecraft:soul_campfire", - "id" : 622 - }, - { - "name" : "minecraft:soul_fire", - "id" : -237 - }, - { - "name" : "minecraft:soul_lantern", - "id" : -269 - }, - { - "name" : "minecraft:soul_sand", - "id" : 88 - }, - { - "name" : "minecraft:soul_soil", - "id" : -236 - }, - { - "name" : "minecraft:soul_torch", - "id" : -268 - }, - { - "name" : "minecraft:sparkler", - "id" : 600 - }, - { - "name" : "minecraft:spawn_egg", - "id" : 652 - }, - { - "name" : "minecraft:spider_eye", - "id" : 278 - }, - { - "name" : "minecraft:spider_spawn_egg", - "id" : 446 - }, - { - "name" : "minecraft:splash_potion", - "id" : 561 - }, - { - "name" : "minecraft:sponge", - "id" : 19 - }, - { - "name" : "minecraft:spore_blossom", - "id" : -321 - }, - { - "name" : "minecraft:spruce_boat", - "id" : 378 - }, - { - "name" : "minecraft:spruce_button", - "id" : -144 - }, - { - "name" : "minecraft:spruce_chest_boat", - "id" : 641 - }, - { - "name" : "minecraft:spruce_door", - "id" : 553 - }, - { - "name" : "minecraft:spruce_fence_gate", - "id" : 183 - }, - { - "name" : "minecraft:spruce_pressure_plate", - "id" : -154 - }, - { - "name" : "minecraft:spruce_sign", - "id" : 576 - }, - { - "name" : "minecraft:spruce_stairs", - "id" : 134 - }, - { - "name" : "minecraft:spruce_standing_sign", - "id" : -181 - }, - { - "name" : "minecraft:spruce_trapdoor", - "id" : -149 - }, - { - "name" : "minecraft:spruce_wall_sign", - "id" : -182 - }, - { - "name" : "minecraft:spyglass", - "id" : 625 - }, - { - "name" : "minecraft:squid_spawn_egg", - "id" : 450 - }, - { - "name" : "minecraft:stained_glass", - "id" : 241 - }, - { - "name" : "minecraft:stained_glass_pane", - "id" : 160 - }, - { - "name" : "minecraft:stained_hardened_clay", - "id" : 159 - }, - { - "name" : "minecraft:standing_banner", - "id" : 176 - }, - { - "name" : "minecraft:standing_sign", - "id" : 63 - }, - { - "name" : "minecraft:stick", - "id" : 320 - }, - { - "name" : "minecraft:sticky_piston", - "id" : 29 - }, - { - "name" : "minecraft:sticky_piston_arm_collision", - "id" : -217 - }, - { - "name" : "minecraft:stone", - "id" : 1 - }, - { - "name" : "minecraft:stone_axe", - "id" : 315 - }, - { - "name" : "minecraft:stone_block_slab", - "id" : 44 - }, - { - "name" : "minecraft:stone_block_slab2", - "id" : 182 - }, - { - "name" : "minecraft:stone_block_slab3", - "id" : -162 - }, - { - "name" : "minecraft:stone_block_slab4", - "id" : -166 - }, - { - "name" : "minecraft:stone_brick_stairs", - "id" : 109 - }, - { - "name" : "minecraft:stone_button", - "id" : 77 - }, - { - "name" : "minecraft:stone_hoe", - "id" : 330 - }, - { - "name" : "minecraft:stone_pickaxe", - "id" : 314 - }, - { - "name" : "minecraft:stone_pressure_plate", - "id" : 70 - }, - { - "name" : "minecraft:stone_shovel", - "id" : 313 - }, - { - "name" : "minecraft:stone_stairs", - "id" : 67 - }, - { - "name" : "minecraft:stone_sword", - "id" : 312 - }, - { - "name" : "minecraft:stonebrick", - "id" : 98 - }, - { - "name" : "minecraft:stonecutter", - "id" : 245 - }, - { - "name" : "minecraft:stonecutter_block", - "id" : -197 - }, - { - "name" : "minecraft:stray_spawn_egg", - "id" : 462 - }, - { - "name" : "minecraft:strider_spawn_egg", - "id" : 495 - }, - { - "name" : "minecraft:string", - "id" : 326 - }, - { - "name" : "minecraft:stripped_acacia_log", - "id" : -8 - }, - { - "name" : "minecraft:stripped_birch_log", - "id" : -6 - }, - { - "name" : "minecraft:stripped_crimson_hyphae", - "id" : -300 - }, - { - "name" : "minecraft:stripped_crimson_stem", - "id" : -240 - }, - { - "name" : "minecraft:stripped_dark_oak_log", - "id" : -9 - }, - { - "name" : "minecraft:stripped_jungle_log", - "id" : -7 - }, - { - "name" : "minecraft:stripped_mangrove_log", - "id" : -485 - }, - { - "name" : "minecraft:stripped_mangrove_wood", - "id" : -498 - }, - { - "name" : "minecraft:stripped_oak_log", - "id" : -10 - }, - { - "name" : "minecraft:stripped_spruce_log", - "id" : -5 - }, - { - "name" : "minecraft:stripped_warped_hyphae", - "id" : -301 - }, - { - "name" : "minecraft:stripped_warped_stem", - "id" : -241 - }, - { - "name" : "minecraft:structure_block", - "id" : 252 - }, - { - "name" : "minecraft:structure_void", - "id" : 217 - }, - { - "name" : "minecraft:sugar", - "id" : 416 - }, - { - "name" : "minecraft:sugar_cane", - "id" : 385 - }, - { - "name" : "minecraft:suspicious_stew", - "id" : 590 - }, - { - "name" : "minecraft:sweet_berries", - "id" : 287 - }, - { - "name" : "minecraft:sweet_berry_bush", - "id" : -207 - }, - { - "name" : "minecraft:tadpole_bucket", - "id" : 630 - }, - { - "name" : "minecraft:tadpole_spawn_egg", - "id" : 629 - }, - { - "name" : "minecraft:tallgrass", - "id" : 31 - }, - { - "name" : "minecraft:target", - "id" : -239 - }, - { - "name" : "minecraft:tinted_glass", - "id" : -334 - }, - { - "name" : "minecraft:tnt", - "id" : 46 - }, - { - "name" : "minecraft:tnt_minecart", - "id" : 525 - }, - { - "name" : "minecraft:torch", - "id" : 50 - }, - { - "name" : "minecraft:totem_of_undying", - "id" : 568 - }, - { - "name" : "minecraft:trader_llama_spawn_egg", - "id" : 648 - }, - { - "name" : "minecraft:trapdoor", - "id" : 96 - }, - { - "name" : "minecraft:trapped_chest", - "id" : 146 - }, - { - "name" : "minecraft:trident", - "id" : 546 - }, - { - "name" : "minecraft:trip_wire", - "id" : 132 - }, - { - "name" : "minecraft:tripwire_hook", - "id" : 131 - }, - { - "name" : "minecraft:tropical_fish", - "id" : 266 - }, - { - "name" : "minecraft:tropical_fish_bucket", - "id" : 366 - }, - { - "name" : "minecraft:tropical_fish_spawn_egg", - "id" : 479 - }, - { - "name" : "minecraft:tuff", - "id" : -333 - }, - { - "name" : "minecraft:turtle_egg", - "id" : -159 - }, - { - "name" : "minecraft:turtle_helmet", - "id" : 573 - }, - { - "name" : "minecraft:turtle_spawn_egg", - "id" : 485 - }, - { - "name" : "minecraft:twisting_vines", - "id" : -287 - }, - { - "name" : "minecraft:underwater_torch", - "id" : 239 - }, - { - "name" : "minecraft:undyed_shulker_box", - "id" : 205 - }, - { - "name" : "minecraft:unknown", - "id" : -305 - }, - { - "name" : "minecraft:unlit_redstone_torch", - "id" : 75 - }, - { - "name" : "minecraft:unpowered_comparator", - "id" : 149 - }, - { - "name" : "minecraft:unpowered_repeater", - "id" : 93 - }, - { - "name" : "minecraft:verdant_froglight", - "id" : -470 - }, - { - "name" : "minecraft:vex_spawn_egg", - "id" : 476 - }, - { - "name" : "minecraft:villager_spawn_egg", - "id" : 449 - }, - { - "name" : "minecraft:vindicator_spawn_egg", - "id" : 474 - }, - { - "name" : "minecraft:vine", - "id" : 106 - }, - { - "name" : "minecraft:wall_banner", - "id" : 177 - }, - { - "name" : "minecraft:wall_sign", - "id" : 68 - }, - { - "name" : "minecraft:wandering_trader_spawn_egg", - "id" : 492 - }, - { - "name" : "minecraft:warden_spawn_egg", - "id" : 632 - }, - { - "name" : "minecraft:warped_button", - "id" : -261 - }, - { - "name" : "minecraft:warped_door", - "id" : 617 - }, - { - "name" : "minecraft:warped_double_slab", - "id" : -267 - }, - { - "name" : "minecraft:warped_fence", - "id" : -257 - }, - { - "name" : "minecraft:warped_fence_gate", - "id" : -259 - }, - { - "name" : "minecraft:warped_fungus", - "id" : -229 - }, - { - "name" : "minecraft:warped_fungus_on_a_stick", - "id" : 618 - }, - { - "name" : "minecraft:warped_hyphae", - "id" : -298 - }, - { - "name" : "minecraft:warped_nylium", - "id" : -233 - }, - { - "name" : "minecraft:warped_planks", - "id" : -243 - }, - { - "name" : "minecraft:warped_pressure_plate", - "id" : -263 - }, - { - "name" : "minecraft:warped_roots", - "id" : -224 - }, - { - "name" : "minecraft:warped_sign", - "id" : 615 - }, - { - "name" : "minecraft:warped_slab", - "id" : -265 - }, - { - "name" : "minecraft:warped_stairs", - "id" : -255 - }, - { - "name" : "minecraft:warped_standing_sign", - "id" : -251 - }, - { - "name" : "minecraft:warped_stem", - "id" : -226 - }, - { - "name" : "minecraft:warped_trapdoor", - "id" : -247 - }, - { - "name" : "minecraft:warped_wall_sign", - "id" : -253 - }, - { - "name" : "minecraft:warped_wart_block", - "id" : -227 - }, - { - "name" : "minecraft:water", - "id" : 9 - }, - { - "name" : "minecraft:water_bucket", - "id" : 362 - }, - { - "name" : "minecraft:waterlily", - "id" : 111 - }, - { - "name" : "minecraft:waxed_copper", - "id" : -344 - }, - { - "name" : "minecraft:waxed_cut_copper", - "id" : -351 - }, - { - "name" : "minecraft:waxed_cut_copper_slab", - "id" : -365 - }, - { - "name" : "minecraft:waxed_cut_copper_stairs", - "id" : -358 - }, - { - "name" : "minecraft:waxed_double_cut_copper_slab", - "id" : -372 - }, - { - "name" : "minecraft:waxed_exposed_copper", - "id" : -345 - }, - { - "name" : "minecraft:waxed_exposed_cut_copper", - "id" : -352 - }, - { - "name" : "minecraft:waxed_exposed_cut_copper_slab", - "id" : -366 - }, - { - "name" : "minecraft:waxed_exposed_cut_copper_stairs", - "id" : -359 - }, - { - "name" : "minecraft:waxed_exposed_double_cut_copper_slab", - "id" : -373 - }, - { - "name" : "minecraft:waxed_oxidized_copper", - "id" : -446 - }, - { - "name" : "minecraft:waxed_oxidized_cut_copper", - "id" : -447 - }, - { - "name" : "minecraft:waxed_oxidized_cut_copper_slab", - "id" : -449 - }, - { - "name" : "minecraft:waxed_oxidized_cut_copper_stairs", - "id" : -448 - }, - { - "name" : "minecraft:waxed_oxidized_double_cut_copper_slab", - "id" : -450 - }, - { - "name" : "minecraft:waxed_weathered_copper", - "id" : -346 - }, - { - "name" : "minecraft:waxed_weathered_cut_copper", - "id" : -353 - }, - { - "name" : "minecraft:waxed_weathered_cut_copper_slab", - "id" : -367 - }, - { - "name" : "minecraft:waxed_weathered_cut_copper_stairs", - "id" : -360 - }, - { - "name" : "minecraft:waxed_weathered_double_cut_copper_slab", - "id" : -374 - }, - { - "name" : "minecraft:weathered_copper", - "id" : -342 - }, - { - "name" : "minecraft:weathered_cut_copper", - "id" : -349 - }, - { - "name" : "minecraft:weathered_cut_copper_slab", - "id" : -363 - }, - { - "name" : "minecraft:weathered_cut_copper_stairs", - "id" : -356 - }, - { - "name" : "minecraft:weathered_double_cut_copper_slab", - "id" : -370 - }, - { - "name" : "minecraft:web", - "id" : 30 - }, - { - "name" : "minecraft:weeping_vines", - "id" : -231 - }, - { - "name" : "minecraft:wheat", - "id" : 334 - }, - { - "name" : "minecraft:wheat_seeds", - "id" : 291 - }, - { - "name" : "minecraft:white_candle", - "id" : -413 - }, - { - "name" : "minecraft:white_candle_cake", - "id" : -430 - }, - { - "name" : "minecraft:white_dye", - "id" : 410 - }, - { - "name" : "minecraft:white_glazed_terracotta", - "id" : 220 - }, - { - "name" : "minecraft:witch_spawn_egg", - "id" : 452 - }, - { - "name" : "minecraft:wither_rose", - "id" : -216 - }, - { - "name" : "minecraft:wither_skeleton_spawn_egg", - "id" : 464 - }, - { - "name" : "minecraft:wolf_spawn_egg", - "id" : 439 - }, - { - "name" : "minecraft:wood", - "id" : -212 - }, - { - "name" : "minecraft:wooden_axe", - "id" : 311 - }, - { - "name" : "minecraft:wooden_button", - "id" : 143 - }, - { - "name" : "minecraft:wooden_door", - "id" : 359 - }, - { - "name" : "minecraft:wooden_hoe", - "id" : 329 - }, - { - "name" : "minecraft:wooden_pickaxe", - "id" : 310 - }, - { - "name" : "minecraft:wooden_pressure_plate", - "id" : 72 - }, - { - "name" : "minecraft:wooden_shovel", - "id" : 309 - }, - { - "name" : "minecraft:wooden_slab", - "id" : 158 - }, - { - "name" : "minecraft:wooden_sword", - "id" : 308 - }, - { - "name" : "minecraft:wool", - "id" : 35 - }, - { - "name" : "minecraft:writable_book", - "id" : 510 - }, - { - "name" : "minecraft:written_book", - "id" : 511 - }, - { - "name" : "minecraft:yellow_candle", - "id" : -417 - }, - { - "name" : "minecraft:yellow_candle_cake", - "id" : -434 - }, - { - "name" : "minecraft:yellow_dye", - "id" : 406 - }, - { - "name" : "minecraft:yellow_flower", - "id" : 37 - }, - { - "name" : "minecraft:yellow_glazed_terracotta", - "id" : 224 - }, - { - "name" : "minecraft:zoglin_spawn_egg", - "id" : 498 - }, - { - "name" : "minecraft:zombie_horse_spawn_egg", - "id" : 468 - }, - { - "name" : "minecraft:zombie_pigman_spawn_egg", - "id" : 448 - }, - { - "name" : "minecraft:zombie_spawn_egg", - "id" : 447 - }, - { - "name" : "minecraft:zombie_villager_spawn_egg", - "id" : 477 - } -] \ No newline at end of file From b09caed0f1e19e85a78043fd79348f87385e228e Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Fri, 2 Dec 2022 00:29:20 -0500 Subject: [PATCH 264/290] Fix BitSet import --- .../src/main/java/org/geysermc/geyser/session/GeyserSession.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 8da5b1273..8f89e81f1 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -194,6 +194,7 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.HashSet; import java.util.List; From 309f9737bb70dc474c09b81578a2346cd772a9d7 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Fri, 2 Dec 2022 01:43:09 -0500 Subject: [PATCH 265/290] Update palettes/mappings --- .../resources/bedrock/biome_definitions.dat | Bin 42385 -> 2605093 bytes .../bedrock/creative_items.1_19_50.json | 93 ++++++++++++++++++ .../resources/bedrock/entity_identifiers.dat | Bin 7762 -> 7823 bytes core/src/main/resources/mappings | 2 +- 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index 0520c61e28fdd87c24bfdfc25fa30f3f52b70eee..47b19ab44fbfbf531f82c14cbceaad74d87afe47 100644 GIT binary patch literal 2605093 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%0Dr|j|qX{c2 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

    _$5>vWeDnm=+-ais~iGb2nk|k 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 Smn@;KMDP@7D?Fubz4d<}Lt$J1 diff --git a/core/src/main/resources/bedrock/creative_items.1_19_50.json b/core/src/main/resources/bedrock/creative_items.1_19_50.json index 243826c9e..4ed5f8194 100644 --- a/core/src/main/resources/bedrock/creative_items.1_19_50.json +++ b/core/src/main/resources/bedrock/creative_items.1_19_50.json @@ -28,6 +28,14 @@ "id" : "minecraft:mangrove_planks", "blockRuntimeId" : 1570 }, + { + "id" : "minecraft:bamboo_planks", + "blockRuntimeId" : 8202 + }, + { + "id" : "minecraft:bamboo_mosaic", + "blockRuntimeId" : 12438 + }, { "id" : "minecraft:crimson_planks", "blockRuntimeId" : 7399 @@ -152,6 +160,10 @@ "id" : "minecraft:mangrove_fence", "blockRuntimeId" : 10405 }, + { + "id" : "minecraft:bamboo_fence", + "blockRuntimeId" : 863 + }, { "id" : "minecraft:nether_brick_fence", "blockRuntimeId" : 6071 @@ -192,6 +204,10 @@ "id" : "minecraft:mangrove_fence_gate", "blockRuntimeId" : 6406 }, + { + "id" : "minecraft:bamboo_fence_gate", + "blockRuntimeId" : 7611 + }, { "id" : "minecraft:crimson_fence_gate", "blockRuntimeId" : 6826 @@ -240,6 +256,14 @@ "id" : "minecraft:mangrove_stairs", "blockRuntimeId" : 6376 }, + { + "id" : "minecraft:bamboo_stairs", + "blockRuntimeId" : 1339 + }, + { + "id" : "minecraft:bamboo_mosaic_stairs", + "blockRuntimeId" : 9958 + }, { "id" : "minecraft:stone_brick_stairs", "blockRuntimeId" : 1554 @@ -421,6 +445,9 @@ { "id" : "minecraft:mangrove_door" }, + { + "id" : "minecraft:bamboo_door" + }, { "id" : "minecraft:iron_door" }, @@ -458,6 +485,10 @@ "id" : "minecraft:mangrove_trapdoor", "blockRuntimeId" : 6266 }, + { + "id" : "minecraft:bamboo_trapdoor", + "blockRuntimeId" : 7828 + }, { "id" : "minecraft:iron_trapdoor", "blockRuntimeId" : 549 @@ -666,6 +697,14 @@ "id" : "minecraft:mangrove_slab", "blockRuntimeId" : 1772 }, + { + "id" : "minecraft:bamboo_slab", + "blockRuntimeId" : 10300 + }, + { + "id" : "minecraft:bamboo_mosaic_slab", + "blockRuntimeId" : 4081 + }, { "id" : "minecraft:stone_block_slab", "blockRuntimeId" : 6054 @@ -2707,6 +2746,9 @@ { "id" : "minecraft:trader_llama_spawn_egg" }, + { + "id" : "minecraft:camel_spawn_egg" + }, { "id" : "minecraft:ghast_spawn_egg" }, @@ -4073,6 +4115,10 @@ "id" : "minecraft:bookshelf", "blockRuntimeId" : 10443 }, + { + "id" : "minecraft:chiseled_bookshelf", + "blockRuntimeId" : 326 + }, { "id" : "minecraft:lectern", "blockRuntimeId" : 10718 @@ -4263,12 +4309,45 @@ { "id" : "minecraft:mangrove_sign" }, + { + "id" : "minecraft:bamboo_sign" + }, { "id" : "minecraft:crimson_sign" }, { "id" : "minecraft:warped_sign" }, + { + "id" : "minecraft:oak_hanging_sign" + }, + { + "id" : "minecraft:spruce_hanging_sign" + }, + { + "id" : "minecraft:birch_hanging_sign" + }, + { + "id" : "minecraft:jungle_hanging_sign" + }, + { + "id" : "minecraft:acacia_hanging_sign" + }, + { + "id" : "minecraft:dark_oak_hanging_sign" + }, + { + "id" : "minecraft:crimson_hanging_sign" + }, + { + "id" : "minecraft:warped_hanging_sign" + }, + { + "id" : "minecraft:mangrove_hanging_sign" + }, + { + "id" : "minecraft:bamboo_hanging_sign" + }, { "id" : "minecraft:painting" }, @@ -4979,6 +5058,9 @@ { "id" : "minecraft:mangrove_boat" }, + { + "id" : "minecraft:bamboo_raft" + }, { "id" : "minecraft:oak_chest_boat" }, @@ -5000,6 +5082,9 @@ { "id" : "minecraft:mangrove_chest_boat" }, + { + "id" : "minecraft:bamboo_chest_raft" + }, { "id" : "minecraft:rail", "blockRuntimeId" : 5697 @@ -5071,6 +5156,10 @@ "id" : "minecraft:mangrove_button", "blockRuntimeId" : 10840 }, + { + "id" : "minecraft:bamboo_button", + "blockRuntimeId" : 10238 + }, { "id" : "minecraft:stone_button", "blockRuntimeId" : 826 @@ -5119,6 +5208,10 @@ "id" : "minecraft:mangrove_pressure_plate", "blockRuntimeId" : 5646 }, + { + "id" : "minecraft:bamboo_pressure_plate", + "blockRuntimeId" : 9819 + }, { "id" : "minecraft:crimson_pressure_plate", "blockRuntimeId" : 12447 diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index 297d30537148f5cb80ecd63810b352f3e4c7ab03..8f0c9ce8ef8f468bf6b1f2b530a131b33f6023c2 100644 GIT binary patch delta 58 zcmV-A0LA~(JdZsM3IGWPX=H3^b94&w0h2)i7?aEk3$ZZX9g&a|lfVND3}az!Wo!cj Qa%p6g0+XQ(6O#@eL@PfMnE(I) delta 34 qcmeCTy=247#lXpynUa%PT*CE%ak3+$#N;#F+#3z<$xil`a{&OlNecr2 diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 19094e360..5bd26dd73 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 19094e36080d78212534f5f0d073fb5d3f68a89f +Subproject commit 5bd26dd735bd89dd50e5c55a0d022f7c70916300 From cc3037d6c53400b4f1a33e7bc5e4be239e6f1331 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 2 Dec 2022 14:11:56 -0500 Subject: [PATCH 266/290] Update to 1.19.3-rc1; various changes and fixes --- .../manager/GeyserSpigotWorldManager.java | 10 +- .../org/geysermc/geyser/level/GameRule.java | 117 +++++++----------- .../geyser/level/GeyserWorldManager.java | 25 +--- .../geysermc/geyser/level/WorldManager.java | 16 ++- .../protocol/java/JavaCommandsTranslator.java | 33 +++-- .../entity/JavaSoundEntityTranslator.java | 2 +- .../JavaPlayerInfoRemoveTranslator.java | 4 +- .../JavaPlayerInfoUpdateTranslator.java | 66 +++++----- .../java/level/JavaCustomSoundTranslator.java | 49 -------- .../java/level/JavaSoundTranslator.java | 2 +- .../geysermc/geyser/util/SettingsUtils.java | 10 +- .../org/geysermc/geyser/util/SoundUtils.java | 28 ++--- 12 files changed, 134 insertions(+), 228 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 7bb8f1666..52f29dcfe 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -38,7 +38,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import org.bukkit.plugin.Plugin; import org.geysermc.geyser.level.GameRule; -import org.geysermc.geyser.level.GeyserWorldManager; +import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; @@ -51,7 +51,7 @@ import java.util.List; /** * The base world manager to use when there is no supported NMS revision */ -public class GeyserSpigotWorldManager extends GeyserWorldManager { +public class GeyserSpigotWorldManager extends WorldManager { private final Plugin plugin; public GeyserSpigotWorldManager(Plugin plugin) { @@ -151,12 +151,12 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { return true; } - public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { + public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { String value = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID()); if (!value.isEmpty()) { return Boolean.parseBoolean(value); } - return (Boolean) gameRule.getDefaultValue(); + return gameRule.getDefaultBooleanValue(); } @Override @@ -165,7 +165,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager { if (!value.isEmpty()) { return Integer.parseInt(value); } - return (int) gameRule.getDefaultValue(); + return gameRule.getDefaultIntValue(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/level/GameRule.java b/core/src/main/java/org/geysermc/geyser/level/GameRule.java index be647cff6..015f9c50c 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GameRule.java +++ b/core/src/main/java/org/geysermc/geyser/level/GameRule.java @@ -32,43 +32,41 @@ import lombok.Getter; * It is used to construct the list for the settings menu */ public enum GameRule { - ANNOUNCEADVANCEMENTS("announceAdvancements", Boolean.class, true), // JE only - COMMANDBLOCKOUTPUT("commandBlockOutput", Boolean.class, true), - DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", Boolean.class, false), // JE only - DISABLERAIDS("disableRaids", Boolean.class, false), // JE only - DODAYLIGHTCYCLE("doDaylightCycle", Boolean.class, true), - DOENTITYDROPS("doEntityDrops", Boolean.class, true), - DOFIRETICK("doFireTick", Boolean.class, true), - DOIMMEDIATERESPAWN("doImmediateRespawn", Boolean.class, false), - DOINSOMNIA("doInsomnia", Boolean.class, true), - DOLIMITEDCRAFTING("doLimitedCrafting", Boolean.class, false), // JE only - DOMOBLOOT("doMobLoot", Boolean.class, true), - DOMOBSPAWNING("doMobSpawning", Boolean.class, true), - DOPATROLSPAWNING("doPatrolSpawning", Boolean.class, true), // JE only - DOTILEDROPS("doTileDrops", Boolean.class, true), - DOTRADERSPAWNING("doTraderSpawning", Boolean.class, true), // JE only - DOWEATHERCYCLE("doWeatherCycle", Boolean.class, true), - DROWNINGDAMAGE("drowningDamage", Boolean.class, true), - FALLDAMAGE("fallDamage", Boolean.class, true), - FIREDAMAGE("fireDamage", Boolean.class, true), - FREEZEDAMAGE("freezeDamage", Boolean.class, true), - FORGIVEDEADPLAYERS("forgiveDeadPlayers", Boolean.class, true), // JE only - KEEPINVENTORY("keepInventory", Boolean.class, false), - LOGADMINCOMMANDS("logAdminCommands", Boolean.class, true), // JE only - MAXCOMMANDCHAINLENGTH("maxCommandChainLength", Integer.class, 65536), - MAXENTITYCRAMMING("maxEntityCramming", Integer.class, 24), // JE only - MOBGRIEFING("mobGriefing", Boolean.class, true), - NATURALREGENERATION("naturalRegeneration", Boolean.class, true), - PLAYERSSLEEPINGPERCENTAGE("playersSleepingPercentage", Integer.class, 100), // JE only - RANDOMTICKSPEED("randomTickSpeed", Integer.class, 3), - REDUCEDDEBUGINFO("reducedDebugInfo", Boolean.class, false), // JE only - SENDCOMMANDFEEDBACK("sendCommandFeedback", Boolean.class, true), - SHOWDEATHMESSAGES("showDeathMessages", Boolean.class, true), - SPAWNRADIUS("spawnRadius", Integer.class, 10), - SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", Boolean.class, true), // JE only - UNIVERSALANGER("universalAnger", Boolean.class, false), // JE only - - UNKNOWN("unknown", Object.class); + ANNOUNCEADVANCEMENTS("announceAdvancements", true), // JE only + COMMANDBLOCKOUTPUT("commandBlockOutput", true), + DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", false), // JE only + DISABLERAIDS("disableRaids", false), // JE only + DODAYLIGHTCYCLE("doDaylightCycle", true), + DOENTITYDROPS("doEntityDrops", true), + DOFIRETICK("doFireTick", true), + DOIMMEDIATERESPAWN("doImmediateRespawn", false), + DOINSOMNIA("doInsomnia", true), + DOLIMITEDCRAFTING("doLimitedCrafting", false), // JE only + DOMOBLOOT("doMobLoot", true), + DOMOBSPAWNING("doMobSpawning", true), + DOPATROLSPAWNING("doPatrolSpawning", true), // JE only + DOTILEDROPS("doTileDrops", true), + DOTRADERSPAWNING("doTraderSpawning", true), // JE only + DOWEATHERCYCLE("doWeatherCycle", true), + DROWNINGDAMAGE("drowningDamage", true), + FALLDAMAGE("fallDamage", true), + FIREDAMAGE("fireDamage", true), + FREEZEDAMAGE("freezeDamage", true), + FORGIVEDEADPLAYERS("forgiveDeadPlayers", true), // JE only + KEEPINVENTORY("keepInventory", false), + LOGADMINCOMMANDS("logAdminCommands", true), // JE only + MAXCOMMANDCHAINLENGTH("maxCommandChainLength", 65536), + MAXENTITYCRAMMING("maxEntityCramming", 24), // JE only + MOBGRIEFING("mobGriefing", true), + NATURALREGENERATION("naturalRegeneration", true), + PLAYERSSLEEPINGPERCENTAGE("playersSleepingPercentage", 100), // JE only + RANDOMTICKSPEED("randomTickSpeed", 3), + REDUCEDDEBUGINFO("reducedDebugInfo", false), // JE only + SENDCOMMANDFEEDBACK("sendCommandFeedback", true), + SHOWDEATHMESSAGES("showDeathMessages", true), + SPAWNRADIUS("spawnRadius", 10), + SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", true), // JE only + UNIVERSALANGER("universalAnger", false); // JE only public static final GameRule[] VALUES = values(); @@ -78,48 +76,25 @@ public enum GameRule { @Getter private final Class type; - @Getter - private final Object defaultValue; + private final int defaultValue; - GameRule(String javaID, Class type) { - this(javaID, type, null); + GameRule(String javaID, boolean defaultValue) { + this.javaID = javaID; + this.type = Boolean.class; + this.defaultValue = defaultValue ? 1 : 0; } - GameRule(String javaID, Class type, Object defaultValue) { + GameRule(String javaID, int defaultValue) { this.javaID = javaID; - this.type = type; + this.type = Integer.class; this.defaultValue = defaultValue; } - /** - * Convert a string to an object of the correct type for the current gamerule - * - * @param value The string value to convert - * @return The converted and formatted value - */ - public Object convertValue(String value) { - if (type.equals(Boolean.class)) { - return Boolean.parseBoolean(value); - } else if (type.equals(Integer.class)) { - return Integer.parseInt(value); - } - - return null; + public boolean getDefaultBooleanValue() { + return defaultValue != 0; } - /** - * Fetch a game rule by the given Java ID - * - * @param id The ID of the gamerule - * @return A {@link GameRule} object representing the requested ID or {@link GameRule#UNKNOWN} - */ - public static GameRule fromJavaID(String id) { - for (GameRule gamerule : VALUES) { - if (gamerule.javaID.equals(id)) { - return gamerule; - } - } - - return UNKNOWN; + public int getDefaultIntValue() { + return defaultValue; } } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 100917793..f19060c65 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,8 +25,6 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; @@ -36,11 +34,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; -import java.util.Locale; - public class GeyserWorldManager extends WorldManager { - - private static final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); @Override public int getBlockAt(GeyserSession session, int x, int y, int z) { @@ -82,18 +77,18 @@ public class GeyserWorldManager extends WorldManager { @Override public void setGameRule(GeyserSession session, String name, Object value) { - session.sendCommand("gamerule " + name + " " + value); + super.setGameRule(session, name, value); gameruleCache.put(name, String.valueOf(value)); } @Override - public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { + public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { String value = gameruleCache.get(gameRule.getJavaID()); if (value != null) { return Boolean.parseBoolean(value); } - return gameRule.getDefaultValue() != null ? (Boolean) gameRule.getDefaultValue() : false; + return gameRule.getDefaultBooleanValue(); } @Override @@ -103,17 +98,7 @@ public class GeyserWorldManager extends WorldManager { return Integer.parseInt(value); } - return gameRule.getDefaultValue() != null ? (int) gameRule.getDefaultValue() : 0; - } - - @Override - public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { - session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT)); - } - - @Override - public void setDifficulty(GeyserSession session, Difficulty difficulty) { - session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); + return gameRule.getDefaultIntValue(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index 69f5d5beb..b3a727d26 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -31,6 +31,8 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import org.geysermc.geyser.session.GeyserSession; +import java.util.Locale; + /** * Class that manages or retrieves various information * from the world. Everything in this class should be @@ -105,7 +107,9 @@ public abstract class WorldManager { * @param name The gamerule to change * @param value The new value for the gamerule */ - public abstract void setGameRule(GeyserSession session, String name, Object value); + public void setGameRule(GeyserSession session, String name, Object value) { + session.sendCommand("gamerule " + name + " " + value); + } /** * Gets a gamerule value as a boolean @@ -114,7 +118,7 @@ public abstract class WorldManager { * @param gameRule The gamerule to fetch the value of * @return The boolean representation of the value */ - public abstract Boolean getGameRuleBool(GeyserSession session, GameRule gameRule); + public abstract boolean getGameRuleBool(GeyserSession session, GameRule gameRule); /** * Get a gamerule value as an integer @@ -131,7 +135,9 @@ public abstract class WorldManager { * @param session The session of the player to change the game mode of * @param gameMode The game mode to change the player to */ - public abstract void setPlayerGameMode(GeyserSession session, GameMode gameMode); + public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { + session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT)); + } /** * Change the difficulty of the Java server @@ -139,7 +145,9 @@ public abstract class WorldManager { * @param session The session of the user that requested the change * @param difficulty The difficulty to change to */ - public abstract void setDifficulty(GeyserSession session, Difficulty difficulty); + public void setDifficulty(GeyserSession session, Difficulty difficulty) { + session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); + } /** * Checks if the given session's player has a permission diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 8f4e46454..14ff1a51a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -234,18 +234,18 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.OPERATOR; // ">=", "==", etc case BLOCK_STATE -> BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.get().keySet().toArray(new String[0]); case ITEM_STACK -> session.getItemMappings().getItemNames(); - case ITEM_ENCHANTMENT -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS; - case ENTITY_SUMMON -> Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0]); case COLOR -> VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; - case MOB_EFFECT -> ALL_EFFECT_IDENTIFIERS; case RESOURCE, RESOURCE_OR_TAG -> { String resource = ((ResourceProperties) node.getProperties()).getRegistryKey(); - if (resource.equals("minecraft:attribute")) { - yield ATTRIBUTES; - } else { - yield CommandParam.STRING; - } + yield switch (resource) { + // minecraft:worldgen/biome is also valid but we currently don't cache biome IDs + case "minecraft:attribute" -> ATTRIBUTES; + case "minecraft:enchantment" -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS; + case "minecraft:entity_type" -> Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0]); + case "minecraft:mob_effect" -> ALL_EFFECT_IDENTIFIERS; + default -> CommandParam.STRING; + }; } default -> CommandParam.STRING; }; @@ -325,7 +325,7 @@ public class JavaCommandsTranslator extends PacketTranslator diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java index 06f141aa6..68f310db4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java @@ -40,6 +40,6 @@ public class JavaSoundEntityTranslator extends PacketTranslator + // We'll send our own PlayerListEntry in requestAndHandleSkinAndCape + // But we need to send other player's entries so they show up in the player list + // without processing their skin information - that'll be processed when they spawn in + if (self) { + SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername())); - } else { - playerEntity.setValid(true); - PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity); + } else { + playerEntity.setValid(true); + PlayerListPacket.Entry playerListEntry = SkinManager.buildCachedEntry(session, playerEntity); - translate.getEntries().add(playerListEntry); - } + translate.getEntries().add(playerListEntry); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java deleted file mode 100644 index 00894bd8b..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.translator.protocol.java.level; - -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundCustomSoundPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.SoundUtils; - -@Translator(packet = ClientboundCustomSoundPacket.class) -public class JavaCustomSoundTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundCustomSoundPacket packet) { - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound(SoundUtils.translatePlaySound(packet.getSound())); - playSoundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - playSoundPacket.setVolume(packet.getVolume()); - playSoundPacket.setPitch(packet.getPitch()); - - session.sendUpstreamPacket(playSoundPacket); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java index 5b83ff551..8bd1d94d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java @@ -38,6 +38,6 @@ public class JavaSoundTranslator extends PacketTranslator Date: Sat, 3 Dec 2022 17:20:33 -0500 Subject: [PATCH 267/290] Revert "Drop anything below 1.19.50" This reverts commit 58eede37 --- .../geysermc/geyser/network/GameProtocol.java | 18 + .../populator/BlockRegistryPopulator.java | 3 + .../populator/ItemRegistryPopulator.java | 1 + .../BedrockRequestAbilityTranslator.java | 5 + .../geysermc/geyser/util/DimensionUtils.java | 18 +- .../bedrock/block_palette.1_19_20.nbt | Bin 0 -> 55132 bytes .../bedrock/creative_items.1_19_20.json | 5440 +++++++++++++++++ .../bedrock/runtime_item_states.1_19_20.json | 4530 ++++++++++++++ 8 files changed, 10007 insertions(+), 8 deletions(-) create mode 100644 core/src/main/resources/bedrock/block_palette.1_19_20.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_19_20.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_20.json diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 56159cfa8..e85dc689d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -60,6 +60,14 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.V544_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.V545_CODEC.toBuilder() + .minecraftVersion("1.19.21/1.19.22") + .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder() + .minecraftVersion("1.19.30/1.19.31") + .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } @@ -77,6 +85,16 @@ public final class GameProtocol { return null; } + /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ + + public static boolean supports1_19_30(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v554.V554_CODEC.getProtocolVersion(); + } + + public static boolean supports1_19_50(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v560.V560_CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 72116f548..cbab03990 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -29,6 +29,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; +import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; +import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -72,6 +74,7 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() + .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_19_50", Bedrock_v560.V560_CODEC.getProtocolVersion()), emptyMapper) .build(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 645cf17ba..4b218aa7d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -77,6 +77,7 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); + paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.V544_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.V560_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index 44953dfda..fe8150d40 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -43,6 +43,11 @@ public class BedrockRequestAbilityTranslator extends PacketTranslatorX5GfPypkF`Ueo`Ex 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

    N!K?VWkIdC++V5CX^Dc;QTi}}9T=lerttP4d#b zb@t-=s{f05Iog>R1Xnsx(kBjuLM1(5y> z0`qrk9IcJ3+X^bauWCFyv*Q|9W3$obUsIWO6GmRVc&~n)wYRmd-o(d};}KuUSvr_< zo?aev3X z@?O();jB+SQW0T>*lBV|#ERayqI6_69C>_wlrJ2B*~T_zyVA)LGk_H(QOpU&q^aPc zgIaaCmZOZhK#J7-|J%$y!aAdFvA{53{F3{;m8ORSjLa;Yd0HZz1AiZcz$hmDM`Awa zn{-Jc@GLf5N>k!DrZJRc<1Di;v;f9x^n#gwRmlZFpeT_!p?pUzZBF&mka*oEPSx^3 z%4?=6**e=DBe_)h1LL%53-I%rtiTCBzA~3~2^a{$*?Ucsrhl{dEK;Yra)wkk6D;f` zTGJY90D-s%PIKUCK4_XQuZ!y-86EpCGadf7nMeO+rrdvH=H-8HrUaJBX=-j)FB5`v zQIKt9Qv^8%>R&&^`QnSxu&Fp5}1Li)>l8YTv9@r0ZJG;P5AP^?cZ9k;c1oTm@6?}pJ zIzgZEZyyB>sSSb4mB%**{(%8@LZt)k{ASHq_V=ML1%3ZzX666fOlaPgjik=}JWRvd z?+W4I@6-2dtjAl;)4`RdKUK2&n$d0piAM?yg}^}O7o^ZzRG4s>o2^<>lpu37+`n>F zuqyr-85+24$wO9Q)v)eIJ?^yZpk^agqM~c~^5}C*Mt3)pwabX8U4Nd__3uP7Z->8O zKwPFCId^Pi0`xyHR#^k9M&`)F7Hs@kBQ5%K94Lx^#YN~G4y%nvc$ur@K>|$EG zAKNdmu)?UQPP2YS zU=&B@Ra9zNLe2ROO+n^5G1=p$??b{bYTsXUWu8g(qoWFqbDVo8GMsqN@FsYKVTl z8lK9|?b-#)Zwz9VH%lp}R{E-1_D8c(moRQtfWn;P2kME5d;EbqxtsOQ1YUdN?gTlp vX!0f2XX*s~rfjqL4L=}#m+!XCdF;?V!=^KE4f37S^XE`*=^ZZ(bcp{2Ge*tJ literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_19_20.json b/core/src/main/resources/bedrock/creative_items.1_19_20.json new file mode 100644 index 000000000..98d9e007a --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_19_20.json @@ -0,0 +1,5440 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6073 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6074 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6075 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6076 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6077 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6078 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 949 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 4852 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 922 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1184 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1185 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1186 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1187 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1188 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1189 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1196 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1191 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1192 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1190 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1193 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1197 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1194 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1195 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 3932 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 6726 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 973 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 8084 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 5073 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 7819 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 431 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 732 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7366 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7367 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7368 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7369 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7370 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7371 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 6635 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 4292 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 7998 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 5855 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6586 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 3779 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5367 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 7588 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 4175 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 4627 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 4663 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 5401 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 635 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 3710 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 4094 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 273 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 128 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 7005 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 6969 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 6202 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 5065 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 4597 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 933 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5885 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 3589 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 3629 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 5352 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 5548 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 3539 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 4152 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4393 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6716 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 5310 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 7030 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 6532 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 106 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6604 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 6384 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 4769 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 7702 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 7757 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 7265 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 7432 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 206 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 6282 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 3720 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 7021 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 4299 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 4479 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 4606 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4589 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 4307 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 353 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 395 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 3904 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 6169 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 5842 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4655 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 294 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 7424 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 5524 + }, + { + "id" : "minecraft:wooden_door" + }, + { + "id" : "minecraft:spruce_door" + }, + { + "id" : "minecraft:birch_door" + }, + { + "id" : "minecraft:jungle_door" + }, + { + "id" : "minecraft:acacia_door" + }, + { + "id" : "minecraft:dark_oak_door" + }, + { + "id" : "minecraft:mangrove_door" + }, + { + "id" : "minecraft:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 229 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 6554 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 6652 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 5383 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 5591 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 7504 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 4487 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 321 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 4335 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 4735 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 4803 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 6166 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1135 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1143 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1142 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1150 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1147 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1149 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1136 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1139 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1140 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1148 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1144 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1138 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1146 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1145 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1137 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1141 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 5977 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4854 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4862 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4861 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4869 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4866 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4868 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4855 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4858 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4859 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4867 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4857 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4864 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4856 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4860 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 8264 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 3573 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4272 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5824 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4275 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5272 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5273 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5274 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5275 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5276 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5277 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1151 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5822 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4273 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5825 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5796 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5790 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5826 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5807 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5812 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5813 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5810 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5809 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5808 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4279 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5797 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5806 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4278 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5823 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5791 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5792 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5793 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5794 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 5902 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 6486 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 912 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6020 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 4194 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 5237 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 6602 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 6055 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5284 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7817 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 249 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 6547 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 710 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 7312 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4293 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 3718 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 3912 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 4767 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 7251 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 4554 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6353 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6549 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6551 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6552 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 281 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6089 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 4682 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 7216 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4588 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 5064 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4583 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 4162 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 5466 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 5366 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 5236 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 3617 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 6672 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 4584 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3657 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3658 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6582 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6583 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6584 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6585 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 5400 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 7981 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 291 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 8263 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 4653 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 595 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 8248 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 3555 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7736 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 696 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 709 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7544 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 4691 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 6168 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7199 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5480 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7295 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 3811 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 4853 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1161 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 272 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 4288 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 8262 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 5271 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 363 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3700 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3701 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6087 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6088 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 4235 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 4478 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 697 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 4236 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 7274 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 146 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 3777 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 8261 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3460 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3468 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3467 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3475 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3472 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3474 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3461 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3464 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3465 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3473 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3469 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3463 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3471 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3470 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3462 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3466 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 951 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 959 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 958 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 966 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 963 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 965 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 952 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 955 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 956 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 964 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 960 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 954 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 962 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 961 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 953 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 957 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6266 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6274 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6273 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6281 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6278 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6267 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6270 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6271 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6279 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6275 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6269 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6277 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6276 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6268 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6272 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 662 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 670 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 669 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 677 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 674 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 676 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 663 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 666 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 667 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 675 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 671 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 665 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 673 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 672 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 664 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 668 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 7126 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 643 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6178 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6186 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6185 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6193 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6190 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6192 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6182 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6183 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6191 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6187 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6188 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6180 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6184 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 5575 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 3533 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 8255 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 5836 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 3549 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 4169 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 1153 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 915 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 223 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 6612 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 5360 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 5473 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 5467 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 7013 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 967 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 6541 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7718 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 283 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 6891 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 4295 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 5907 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 5063 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 4191 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 4351 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 24 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 1159 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 5832 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5753 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5754 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 3914 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 6977 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 8083 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 4652 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 3685 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 6686 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 655 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 4692 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 914 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 4363 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 7701 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 4291 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 4289 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 3556 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 7349 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 4503 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 27 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 6109 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 7275 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 6108 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 8040 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 7264 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 6618 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 6352 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 7198 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 105 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 8289 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 656 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 658 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 660 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 7587 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 253 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 657 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 659 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 661 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 3684 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 7756 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4197 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4198 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 6988 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6674 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 7545 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6675 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 6290 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6676 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 5974 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6677 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 644 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3832 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 5850 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3833 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 216 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 350 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 8286 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 5899 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 6950 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 6488 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 7402 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3476 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3482 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3477 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3483 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3478 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3484 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3479 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3485 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3480 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3486 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3481 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3487 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 4163 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 4231 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 4296 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 6501 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 5904 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 5581 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6092 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6093 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6094 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6095 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4355 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4356 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 6668 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 7712 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 6341 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 714 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 715 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 716 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 717 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 718 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 719 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 6978 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 5756 + }, + { + "id" : "minecraft:wheat_seeds" + }, + { + "id" : "minecraft:pumpkin_seeds" + }, + { + "id" : "minecraft:melon_seeds" + }, + { + "id" : "minecraft:beetroot_seeds" + }, + { + "id" : "minecraft:wheat" + }, + { + "id" : "minecraft:beetroot" + }, + { + "id" : "minecraft:potato" + }, + { + "id" : "minecraft:poisonous_potato" + }, + { + "id" : "minecraft:carrot" + }, + { + "id" : "minecraft:golden_carrot" + }, + { + "id" : "minecraft:apple" + }, + { + "id" : "minecraft:golden_apple" + }, + { + "id" : "minecraft:enchanted_golden_apple" + }, + { + "id" : "minecraft:melon_block", + "blockRuntimeId" : 394 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 4579 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 7380 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 6687 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 931 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5457 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 930 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5456 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6494 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6492 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6493 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6491 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6495 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6499 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6497 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6498 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6496 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6500 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4618 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4616 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4617 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4615 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4619 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 69 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 67 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 68 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 66 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 70 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 246 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 7575 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 4364 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 302 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3618 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3619 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3620 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3621 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3622 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3623 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3624 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3625 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3626 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3627 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3628 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5454 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5455 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5458 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5459 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 6167 + }, + { + "id" : "minecraft:white_dye" + }, + { + "id" : "minecraft:light_gray_dye" + }, + { + "id" : "minecraft:gray_dye" + }, + { + "id" : "minecraft:black_dye" + }, + { + "id" : "minecraft:brown_dye" + }, + { + "id" : "minecraft:red_dye" + }, + { + "id" : "minecraft:orange_dye" + }, + { + "id" : "minecraft:yellow_dye" + }, + { + "id" : "minecraft:lime_dye" + }, + { + "id" : "minecraft:green_dye" + }, + { + "id" : "minecraft:cyan_dye" + }, + { + "id" : "minecraft:light_blue_dye" + }, + { + "id" : "minecraft:blue_dye" + }, + { + "id" : "minecraft:purple_dye" + }, + { + "id" : "minecraft:magenta_dye" + }, + { + "id" : "minecraft:pink_dye" + }, + { + "id" : "minecraft:ink_sac" + }, + { + "id" : "minecraft:glow_ink_sac" + }, + { + "id" : "minecraft:cocoa_beans" + }, + { + "id" : "minecraft:lapis_lazuli" + }, + { + "id" : "minecraft:bone_meal" + }, + { + "id" : "minecraft:vine", + "blockRuntimeId" : 896 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 5481 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 5693 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 1160 + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 4679 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 3686 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 4196 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 6691 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 282 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 7029 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 155 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 7418 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 895 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 286 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 6540 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 5399 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 205 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 6177 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 345 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 5982 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 4322 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 7314 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 6890 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 5479 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 5686 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 290 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 7004 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 7812 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 4730 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 4378 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 304 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 349 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 215 + }, + { + "id" : "minecraft:chicken" + }, + { + "id" : "minecraft:porkchop" + }, + { + "id" : "minecraft:beef" + }, + { + "id" : "minecraft:mutton" + }, + { + "id" : "minecraft:rabbit" + }, + { + "id" : "minecraft:cod" + }, + { + "id" : "minecraft:salmon" + }, + { + "id" : "minecraft:tropical_fish" + }, + { + "id" : "minecraft:pufferfish" + }, + { + "id" : "minecraft:brown_mushroom", + "blockRuntimeId" : 3548 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 4587 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 7755 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 287 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7364 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 3613 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7365 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7350 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 6715 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 403 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4146 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4147 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4148 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4149 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4150 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4151 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 4643 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 7273 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 7999 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 4401 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 6437 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 6483 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 3512 + }, + { + "id" : "minecraft:chicken_spawn_egg" + }, + { + "id" : "minecraft:bee_spawn_egg" + }, + { + "id" : "minecraft:cow_spawn_egg" + }, + { + "id" : "minecraft:pig_spawn_egg" + }, + { + "id" : "minecraft:sheep_spawn_egg" + }, + { + "id" : "minecraft:wolf_spawn_egg" + }, + { + "id" : "minecraft:polar_bear_spawn_egg" + }, + { + "id" : "minecraft:ocelot_spawn_egg" + }, + { + "id" : "minecraft:cat_spawn_egg" + }, + { + "id" : "minecraft:mooshroom_spawn_egg" + }, + { + "id" : "minecraft:bat_spawn_egg" + }, + { + "id" : "minecraft:parrot_spawn_egg" + }, + { + "id" : "minecraft:rabbit_spawn_egg" + }, + { + "id" : "minecraft:llama_spawn_egg" + }, + { + "id" : "minecraft:horse_spawn_egg" + }, + { + "id" : "minecraft:donkey_spawn_egg" + }, + { + "id" : "minecraft:mule_spawn_egg" + }, + { + "id" : "minecraft:skeleton_horse_spawn_egg" + }, + { + "id" : "minecraft:zombie_horse_spawn_egg" + }, + { + "id" : "minecraft:tropical_fish_spawn_egg" + }, + { + "id" : "minecraft:cod_spawn_egg" + }, + { + "id" : "minecraft:pufferfish_spawn_egg" + }, + { + "id" : "minecraft:salmon_spawn_egg" + }, + { + "id" : "minecraft:dolphin_spawn_egg" + }, + { + "id" : "minecraft:turtle_spawn_egg" + }, + { + "id" : "minecraft:panda_spawn_egg" + }, + { + "id" : "minecraft:fox_spawn_egg" + }, + { + "id" : "minecraft:creeper_spawn_egg" + }, + { + "id" : "minecraft:enderman_spawn_egg" + }, + { + "id" : "minecraft:silverfish_spawn_egg" + }, + { + "id" : "minecraft:skeleton_spawn_egg" + }, + { + "id" : "minecraft:wither_skeleton_spawn_egg" + }, + { + "id" : "minecraft:stray_spawn_egg" + }, + { + "id" : "minecraft:slime_spawn_egg" + }, + { + "id" : "minecraft:spider_spawn_egg" + }, + { + "id" : "minecraft:zombie_spawn_egg" + }, + { + "id" : "minecraft:zombie_pigman_spawn_egg" + }, + { + "id" : "minecraft:husk_spawn_egg" + }, + { + "id" : "minecraft:drowned_spawn_egg" + }, + { + "id" : "minecraft:squid_spawn_egg" + }, + { + "id" : "minecraft:glow_squid_spawn_egg" + }, + { + "id" : "minecraft:cave_spider_spawn_egg" + }, + { + "id" : "minecraft:witch_spawn_egg" + }, + { + "id" : "minecraft:guardian_spawn_egg" + }, + { + "id" : "minecraft:elder_guardian_spawn_egg" + }, + { + "id" : "minecraft:endermite_spawn_egg" + }, + { + "id" : "minecraft:magma_cube_spawn_egg" + }, + { + "id" : "minecraft:strider_spawn_egg" + }, + { + "id" : "minecraft:hoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_spawn_egg" + }, + { + "id" : "minecraft:zoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_brute_spawn_egg" + }, + { + "id" : "minecraft:goat_spawn_egg" + }, + { + "id" : "minecraft:axolotl_spawn_egg" + }, + { + "id" : "minecraft:warden_spawn_egg" + }, + { + "id" : "minecraft:allay_spawn_egg" + }, + { + "id" : "minecraft:frog_spawn_egg" + }, + { + "id" : "minecraft:tadpole_spawn_egg" + }, + { + "id" : "minecraft:trader_llama_spawn_egg" + }, + { + "id" : "minecraft:ghast_spawn_egg" + }, + { + "id" : "minecraft:blaze_spawn_egg" + }, + { + "id" : "minecraft:shulker_spawn_egg" + }, + { + "id" : "minecraft:vindicator_spawn_egg" + }, + { + "id" : "minecraft:evoker_spawn_egg" + }, + { + "id" : "minecraft:vex_spawn_egg" + }, + { + "id" : "minecraft:villager_spawn_egg" + }, + { + "id" : "minecraft:wandering_trader_spawn_egg" + }, + { + "id" : "minecraft:zombie_villager_spawn_egg" + }, + { + "id" : "minecraft:phantom_spawn_egg" + }, + { + "id" : "minecraft:pillager_spawn_egg" + }, + { + "id" : "minecraft:ravager_spawn_egg" + }, + { + "id" : "minecraft:obsidian", + "blockRuntimeId" : 430 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 6724 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 5833 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 7039 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 8011 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 3838 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 4532 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 5507 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 631 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 632 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5239 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5240 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5241 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5242 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5243 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5244 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5245 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5246 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5247 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5248 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 7038 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 7134 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 3615 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 4391 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 5834 + }, + { + "id" : "minecraft:leather_helmet" + }, + { + "id" : "minecraft:chainmail_helmet" + }, + { + "id" : "minecraft:iron_helmet" + }, + { + "id" : "minecraft:golden_helmet" + }, + { + "id" : "minecraft:diamond_helmet" + }, + { + "id" : "minecraft:netherite_helmet" + }, + { + "id" : "minecraft:leather_chestplate" + }, + { + "id" : "minecraft:chainmail_chestplate" + }, + { + "id" : "minecraft:iron_chestplate" + }, + { + "id" : "minecraft:golden_chestplate" + }, + { + "id" : "minecraft:diamond_chestplate" + }, + { + "id" : "minecraft:netherite_chestplate" + }, + { + "id" : "minecraft:leather_leggings" + }, + { + "id" : "minecraft:chainmail_leggings" + }, + { + "id" : "minecraft:iron_leggings" + }, + { + "id" : "minecraft:golden_leggings" + }, + { + "id" : "minecraft:diamond_leggings" + }, + { + "id" : "minecraft:netherite_leggings" + }, + { + "id" : "minecraft:leather_boots" + }, + { + "id" : "minecraft:chainmail_boots" + }, + { + "id" : "minecraft:iron_boots" + }, + { + "id" : "minecraft:golden_boots" + }, + { + "id" : "minecraft:diamond_boots" + }, + { + "id" : "minecraft:netherite_boots" + }, + { + "id" : "minecraft:wooden_sword" + }, + { + "id" : "minecraft:stone_sword" + }, + { + "id" : "minecraft:iron_sword" + }, + { + "id" : "minecraft:golden_sword" + }, + { + "id" : "minecraft:diamond_sword" + }, + { + "id" : "minecraft:netherite_sword" + }, + { + "id" : "minecraft:wooden_axe" + }, + { + "id" : "minecraft:stone_axe" + }, + { + "id" : "minecraft:iron_axe" + }, + { + "id" : "minecraft:golden_axe" + }, + { + "id" : "minecraft:diamond_axe" + }, + { + "id" : "minecraft:netherite_axe" + }, + { + "id" : "minecraft:wooden_pickaxe" + }, + { + "id" : "minecraft:stone_pickaxe" + }, + { + "id" : "minecraft:iron_pickaxe" + }, + { + "id" : "minecraft:golden_pickaxe" + }, + { + "id" : "minecraft:diamond_pickaxe" + }, + { + "id" : "minecraft:netherite_pickaxe" + }, + { + "id" : "minecraft:wooden_shovel" + }, + { + "id" : "minecraft:stone_shovel" + }, + { + "id" : "minecraft:iron_shovel" + }, + { + "id" : "minecraft:golden_shovel" + }, + { + "id" : "minecraft:diamond_shovel" + }, + { + "id" : "minecraft:netherite_shovel" + }, + { + "id" : "minecraft:wooden_hoe" + }, + { + "id" : "minecraft:stone_hoe" + }, + { + "id" : "minecraft:iron_hoe" + }, + { + "id" : "minecraft:golden_hoe" + }, + { + "id" : "minecraft:diamond_hoe" + }, + { + "id" : "minecraft:netherite_hoe" + }, + { + "id" : "minecraft:bow" + }, + { + "id" : "minecraft:crossbow" + }, + { + "id" : "minecraft:arrow" + }, + { + "id" : "minecraft:arrow", + "damage" : 6 + }, + { + "id" : "minecraft:arrow", + "damage" : 7 + }, + { + "id" : "minecraft:arrow", + "damage" : 8 + }, + { + "id" : "minecraft:arrow", + "damage" : 9 + }, + { + "id" : "minecraft:arrow", + "damage" : 10 + }, + { + "id" : "minecraft:arrow", + "damage" : 11 + }, + { + "id" : "minecraft:arrow", + "damage" : 12 + }, + { + "id" : "minecraft:arrow", + "damage" : 13 + }, + { + "id" : "minecraft:arrow", + "damage" : 14 + }, + { + "id" : "minecraft:arrow", + "damage" : 15 + }, + { + "id" : "minecraft:arrow", + "damage" : 16 + }, + { + "id" : "minecraft:arrow", + "damage" : 17 + }, + { + "id" : "minecraft:arrow", + "damage" : 18 + }, + { + "id" : "minecraft:arrow", + "damage" : 19 + }, + { + "id" : "minecraft:arrow", + "damage" : 20 + }, + { + "id" : "minecraft:arrow", + "damage" : 21 + }, + { + "id" : "minecraft:arrow", + "damage" : 22 + }, + { + "id" : "minecraft:arrow", + "damage" : 23 + }, + { + "id" : "minecraft:arrow", + "damage" : 24 + }, + { + "id" : "minecraft:arrow", + "damage" : 25 + }, + { + "id" : "minecraft:arrow", + "damage" : 26 + }, + { + "id" : "minecraft:arrow", + "damage" : 27 + }, + { + "id" : "minecraft:arrow", + "damage" : 28 + }, + { + "id" : "minecraft:arrow", + "damage" : 29 + }, + { + "id" : "minecraft:arrow", + "damage" : 30 + }, + { + "id" : "minecraft:arrow", + "damage" : 31 + }, + { + "id" : "minecraft:arrow", + "damage" : 32 + }, + { + "id" : "minecraft:arrow", + "damage" : 33 + }, + { + "id" : "minecraft:arrow", + "damage" : 34 + }, + { + "id" : "minecraft:arrow", + "damage" : 35 + }, + { + "id" : "minecraft:arrow", + "damage" : 36 + }, + { + "id" : "minecraft:arrow", + "damage" : 37 + }, + { + "id" : "minecraft:arrow", + "damage" : 38 + }, + { + "id" : "minecraft:arrow", + "damage" : 39 + }, + { + "id" : "minecraft:arrow", + "damage" : 40 + }, + { + "id" : "minecraft:arrow", + "damage" : 41 + }, + { + "id" : "minecraft:arrow", + "damage" : 42 + }, + { + "id" : "minecraft:arrow", + "damage" : 43 + }, + { + "id" : "minecraft:shield" + }, + { + "id" : "minecraft:cooked_chicken" + }, + { + "id" : "minecraft:cooked_porkchop" + }, + { + "id" : "minecraft:cooked_beef" + }, + { + "id" : "minecraft:cooked_mutton" + }, + { + "id" : "minecraft:cooked_rabbit" + }, + { + "id" : "minecraft:cooked_cod" + }, + { + "id" : "minecraft:cooked_salmon" + }, + { + "id" : "minecraft:bread" + }, + { + "id" : "minecraft:mushroom_stew" + }, + { + "id" : "minecraft:beetroot_soup" + }, + { + "id" : "minecraft:rabbit_stew" + }, + { + "id" : "minecraft:baked_potato" + }, + { + "id" : "minecraft:cookie" + }, + { + "id" : "minecraft:pumpkin_pie" + }, + { + "id" : "minecraft:cake" + }, + { + "id" : "minecraft:dried_kelp" + }, + { + "id" : "minecraft:fishing_rod" + }, + { + "id" : "minecraft:carrot_on_a_stick" + }, + { + "id" : "minecraft:warped_fungus_on_a_stick" + }, + { + "id" : "minecraft:snowball" + }, + { + "id" : "minecraft:shears" + }, + { + "id" : "minecraft:flint_and_steel" + }, + { + "id" : "minecraft:lead" + }, + { + "id" : "minecraft:clock" + }, + { + "id" : "minecraft:compass" + }, + { + "id" : "minecraft:recovery_compass" + }, + { + "id" : "minecraft:goat_horn" + }, + { + "id" : "minecraft:goat_horn", + "damage" : 1 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 2 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 3 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 4 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 5 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 6 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 7 + }, + { + "id" : "minecraft:empty_map" + }, + { + "id" : "minecraft:empty_map", + "damage" : 2 + }, + { + "id" : "minecraft:saddle" + }, + { + "id" : "minecraft:leather_horse_armor" + }, + { + "id" : "minecraft:iron_horse_armor" + }, + { + "id" : "minecraft:golden_horse_armor" + }, + { + "id" : "minecraft:diamond_horse_armor" + }, + { + "id" : "minecraft:trident" + }, + { + "id" : "minecraft:turtle_helmet" + }, + { + "id" : "minecraft:elytra" + }, + { + "id" : "minecraft:totem_of_undying" + }, + { + "id" : "minecraft:glass_bottle" + }, + { + "id" : "minecraft:experience_bottle" + }, + { + "id" : "minecraft:potion" + }, + { + "id" : "minecraft:potion", + "damage" : 1 + }, + { + "id" : "minecraft:potion", + "damage" : 2 + }, + { + "id" : "minecraft:potion", + "damage" : 3 + }, + { + "id" : "minecraft:potion", + "damage" : 4 + }, + { + "id" : "minecraft:potion", + "damage" : 5 + }, + { + "id" : "minecraft:potion", + "damage" : 6 + }, + { + "id" : "minecraft:potion", + "damage" : 7 + }, + { + "id" : "minecraft:potion", + "damage" : 8 + }, + { + "id" : "minecraft:potion", + "damage" : 9 + }, + { + "id" : "minecraft:potion", + "damage" : 10 + }, + { + "id" : "minecraft:potion", + "damage" : 11 + }, + { + "id" : "minecraft:potion", + "damage" : 12 + }, + { + "id" : "minecraft:potion", + "damage" : 13 + }, + { + "id" : "minecraft:potion", + "damage" : 14 + }, + { + "id" : "minecraft:potion", + "damage" : 15 + }, + { + "id" : "minecraft:potion", + "damage" : 16 + }, + { + "id" : "minecraft:potion", + "damage" : 17 + }, + { + "id" : "minecraft:potion", + "damage" : 18 + }, + { + "id" : "minecraft:potion", + "damage" : 19 + }, + { + "id" : "minecraft:potion", + "damage" : 20 + }, + { + "id" : "minecraft:potion", + "damage" : 21 + }, + { + "id" : "minecraft:potion", + "damage" : 22 + }, + { + "id" : "minecraft:potion", + "damage" : 23 + }, + { + "id" : "minecraft:potion", + "damage" : 24 + }, + { + "id" : "minecraft:potion", + "damage" : 25 + }, + { + "id" : "minecraft:potion", + "damage" : 26 + }, + { + "id" : "minecraft:potion", + "damage" : 27 + }, + { + "id" : "minecraft:potion", + "damage" : 28 + }, + { + "id" : "minecraft:potion", + "damage" : 29 + }, + { + "id" : "minecraft:potion", + "damage" : 30 + }, + { + "id" : "minecraft:potion", + "damage" : 31 + }, + { + "id" : "minecraft:potion", + "damage" : 32 + }, + { + "id" : "minecraft:potion", + "damage" : 33 + }, + { + "id" : "minecraft:potion", + "damage" : 34 + }, + { + "id" : "minecraft:potion", + "damage" : 35 + }, + { + "id" : "minecraft:potion", + "damage" : 36 + }, + { + "id" : "minecraft:potion", + "damage" : 37 + }, + { + "id" : "minecraft:potion", + "damage" : 38 + }, + { + "id" : "minecraft:potion", + "damage" : 39 + }, + { + "id" : "minecraft:potion", + "damage" : 40 + }, + { + "id" : "minecraft:potion", + "damage" : 41 + }, + { + "id" : "minecraft:potion", + "damage" : 42 + }, + { + "id" : "minecraft:splash_potion" + }, + { + "id" : "minecraft:splash_potion", + "damage" : 1 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 2 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 3 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 4 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 5 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 6 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 7 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 8 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 9 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 10 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 11 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 12 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 13 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 14 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 15 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 16 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 17 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 18 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 19 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 20 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 21 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 22 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 23 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 24 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 25 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 26 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 27 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 28 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 29 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 30 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 31 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 32 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 33 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 34 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 35 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 36 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 37 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 38 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 39 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 40 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 41 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 42 + }, + { + "id" : "minecraft:lingering_potion" + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 1 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 2 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 3 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 4 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 5 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 6 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 7 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 8 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 9 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 10 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 11 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 12 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 13 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 14 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 15 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 16 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 17 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 18 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 19 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 20 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 21 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 22 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 23 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 24 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 25 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 26 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 27 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 28 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 29 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 30 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 31 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 32 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 33 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 34 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 35 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 36 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 37 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 38 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 39 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 40 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 41 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 42 + }, + { + "id" : "minecraft:spyglass" + }, + { + "id" : "minecraft:stick" + }, + { + "id" : "minecraft:bed" + }, + { + "id" : "minecraft:bed", + "damage" : 8 + }, + { + "id" : "minecraft:bed", + "damage" : 7 + }, + { + "id" : "minecraft:bed", + "damage" : 15 + }, + { + "id" : "minecraft:bed", + "damage" : 12 + }, + { + "id" : "minecraft:bed", + "damage" : 14 + }, + { + "id" : "minecraft:bed", + "damage" : 1 + }, + { + "id" : "minecraft:bed", + "damage" : 4 + }, + { + "id" : "minecraft:bed", + "damage" : 5 + }, + { + "id" : "minecraft:bed", + "damage" : 13 + }, + { + "id" : "minecraft:bed", + "damage" : 9 + }, + { + "id" : "minecraft:bed", + "damage" : 3 + }, + { + "id" : "minecraft:bed", + "damage" : 11 + }, + { + "id" : "minecraft:bed", + "damage" : 10 + }, + { + "id" : "minecraft:bed", + "damage" : 2 + }, + { + "id" : "minecraft:bed", + "damage" : 6 + }, + { + "id" : "minecraft:torch", + "blockRuntimeId" : 726 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 4646 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 5857 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 7076 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 5751 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 7405 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 5302 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 364 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 420 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 4571 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 6194 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 6370 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 7372 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 941 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 6226 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 7728 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 7040 + }, + { + "id" : "minecraft:blue_candle" + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 5877 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 688 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 4683 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 171 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 5856 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 8290 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 5835 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 3728 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 6110 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 7804 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 7569 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 649 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 683 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6636 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6640 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6644 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 8041 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 6725 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 6673 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 6942 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 5417 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 7117 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 5585 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 4371 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 4520 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5318 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5326 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5325 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5333 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5330 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5332 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5319 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5322 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5323 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5331 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5327 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5321 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5329 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5328 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5320 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5324 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 348 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 4876 + }, + { + "id" : "minecraft:music_disc_13" + }, + { + "id" : "minecraft:music_disc_cat" + }, + { + "id" : "minecraft:music_disc_blocks" + }, + { + "id" : "minecraft:music_disc_chirp" + }, + { + "id" : "minecraft:music_disc_far" + }, + { + "id" : "minecraft:music_disc_mall" + }, + { + "id" : "minecraft:music_disc_mellohi" + }, + { + "id" : "minecraft:music_disc_stal" + }, + { + "id" : "minecraft:music_disc_strad" + }, + { + "id" : "minecraft:music_disc_ward" + }, + { + "id" : "minecraft:music_disc_11" + }, + { + "id" : "minecraft:music_disc_wait" + }, + { + "id" : "minecraft:music_disc_otherside" + }, + { + "id" : "minecraft:music_disc_5" + }, + { + "id" : "minecraft:music_disc_pigstep" + }, + { + "id" : "minecraft:disc_fragment_5" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 3887 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 251 + }, + { + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 7548 + }, + { + "id" : "minecraft:oak_sign" + }, + { + "id" : "minecraft:spruce_sign" + }, + { + "id" : "minecraft:birch_sign" + }, + { + "id" : "minecraft:jungle_sign" + }, + { + "id" : "minecraft:acacia_sign" + }, + { + "id" : "minecraft:dark_oak_sign" + }, + { + "id" : "minecraft:mangrove_sign" + }, + { + "id" : "minecraft:crimson_sign" + }, + { + "id" : "minecraft:warped_sign" + }, + { + "id" : "minecraft:painting" + }, + { + "id" : "minecraft:frame" + }, + { + "id" : "minecraft:glow_frame" + }, + { + "id" : "minecraft:honey_bottle" + }, + { + "id" : "minecraft:flower_pot" + }, + { + "id" : "minecraft:bowl" + }, + { + "id" : "minecraft:bucket" + }, + { + "id" : "minecraft:milk_bucket" + }, + { + "id" : "minecraft:water_bucket" + }, + { + "id" : "minecraft:lava_bucket" + }, + { + "id" : "minecraft:cod_bucket" + }, + { + "id" : "minecraft:salmon_bucket" + }, + { + "id" : "minecraft:tropical_fish_bucket" + }, + { + "id" : "minecraft:pufferfish_bucket" + }, + { + "id" : "minecraft:powder_snow_bucket" + }, + { + "id" : "minecraft:axolotl_bucket" + }, + { + "id" : "minecraft:tadpole_bucket" + }, + { + "id" : "minecraft:skull", + "damage" : 3 + }, + { + "id" : "minecraft:skull", + "damage" : 2 + }, + { + "id" : "minecraft:skull", + "damage" : 4 + }, + { + "id" : "minecraft:skull", + "damage" : 5 + }, + { + "id" : "minecraft:skull" + }, + { + "id" : "minecraft:skull", + "damage" : 1 + }, + { + "id" : "minecraft:beacon", + "blockRuntimeId" : 145 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 6910 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 4234 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 7576 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 6079 + }, + { + "id" : "minecraft:coal" + }, + { + "id" : "minecraft:charcoal" + }, + { + "id" : "minecraft:diamond" + }, + { + "id" : "minecraft:iron_nugget" + }, + { + "id" : "minecraft:raw_iron" + }, + { + "id" : "minecraft:raw_gold" + }, + { + "id" : "minecraft:raw_copper" + }, + { + "id" : "minecraft:copper_ingot" + }, + { + "id" : "minecraft:iron_ingot" + }, + { + "id" : "minecraft:netherite_scrap" + }, + { + "id" : "minecraft:netherite_ingot" + }, + { + "id" : "minecraft:gold_nugget" + }, + { + "id" : "minecraft:gold_ingot" + }, + { + "id" : "minecraft:emerald" + }, + { + "id" : "minecraft:quartz" + }, + { + "id" : "minecraft:clay_ball" + }, + { + "id" : "minecraft:brick" + }, + { + "id" : "minecraft:netherbrick" + }, + { + "id" : "minecraft:prismarine_shard" + }, + { + "id" : "minecraft:amethyst_shard" + }, + { + "id" : "minecraft:prismarine_crystals" + }, + { + "id" : "minecraft:nautilus_shell" + }, + { + "id" : "minecraft:heart_of_the_sea" + }, + { + "id" : "minecraft:scute" + }, + { + "id" : "minecraft:phantom_membrane" + }, + { + "id" : "minecraft:string" + }, + { + "id" : "minecraft:feather" + }, + { + "id" : "minecraft:flint" + }, + { + "id" : "minecraft:gunpowder" + }, + { + "id" : "minecraft:leather" + }, + { + "id" : "minecraft:rabbit_hide" + }, + { + "id" : "minecraft:rabbit_foot" + }, + { + "id" : "minecraft:fire_charge" + }, + { + "id" : "minecraft:blaze_rod" + }, + { + "id" : "minecraft:blaze_powder" + }, + { + "id" : "minecraft:magma_cream" + }, + { + "id" : "minecraft:fermented_spider_eye" + }, + { + "id" : "minecraft:echo_shard" + }, + { + "id" : "minecraft:dragon_breath" + }, + { + "id" : "minecraft:shulker_shell" + }, + { + "id" : "minecraft:ghast_tear" + }, + { + "id" : "minecraft:slime_ball" + }, + { + "id" : "minecraft:ender_pearl" + }, + { + "id" : "minecraft:ender_eye" + }, + { + "id" : "minecraft:nether_star" + }, + { + "id" : "minecraft:end_rod", + "blockRuntimeId" : 5893 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 1178 + }, + { + "id" : "minecraft:end_crystal" + }, + { + "id" : "minecraft:paper" + }, + { + "id" : "minecraft:book" + }, + { + "id" : "minecraft:writable_book" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:oak_boat" + }, + { + "id" : "minecraft:spruce_boat" + }, + { + "id" : "minecraft:birch_boat" + }, + { + "id" : "minecraft:jungle_boat" + }, + { + "id" : "minecraft:acacia_boat" + }, + { + "id" : "minecraft:dark_oak_boat" + }, + { + "id" : "minecraft:mangrove_boat" + }, + { + "id" : "minecraft:oak_chest_boat" + }, + { + "id" : "minecraft:spruce_chest_boat" + }, + { + "id" : "minecraft:birch_chest_boat" + }, + { + "id" : "minecraft:jungle_chest_boat" + }, + { + "id" : "minecraft:acacia_chest_boat" + }, + { + "id" : "minecraft:dark_oak_chest_boat" + }, + { + "id" : "minecraft:mangrove_chest_boat" + }, + { + "id" : "minecraft:rail", + "blockRuntimeId" : 3922 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 5334 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 4134 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 309 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 3778 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 3527 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 6516 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 6393 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 4323 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 7768 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 116 + }, + { + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 7233 + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 93 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 7064 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 598 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 4434 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 7252 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 7792 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 5916 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 8065 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 3761 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 3557 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 3637 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 5249 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 5958 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 3871 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 8270 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 256 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 3888 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 3667 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 1162 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 6234 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 3515 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 4199 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 7387 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 8015 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 924 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 4366 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 6709 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 3828 + }, + { + "id" : "minecraft:banner" + }, + { + "id" : "minecraft:banner", + "damage" : 8 + }, + { + "id" : "minecraft:banner", + "damage" : 7 + }, + { + "id" : "minecraft:banner", + "damage" : 15 + }, + { + "id" : "minecraft:banner", + "damage" : 12 + }, + { + "id" : "minecraft:banner", + "damage" : 14 + }, + { + "id" : "minecraft:banner", + "damage" : 1 + }, + { + "id" : "minecraft:banner", + "damage" : 4 + }, + { + "id" : "minecraft:banner", + "damage" : 5 + }, + { + "id" : "minecraft:banner", + "damage" : 13 + }, + { + "id" : "minecraft:banner", + "damage" : 9 + }, + { + "id" : "minecraft:banner", + "damage" : 3 + }, + { + "id" : "minecraft:banner", + "damage" : 11 + }, + { + "id" : "minecraft:banner", + "damage" : 10 + }, + { + "id" : "minecraft:banner", + "damage" : 2 + }, + { + "id" : "minecraft:banner", + "damage" : 6 + }, + { + "id" : "minecraft:banner", + "damage" : 15, + "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id" : "minecraft:creeper_banner_pattern" + }, + { + "id" : "minecraft:skull_banner_pattern" + }, + { + "id" : "minecraft:flower_banner_pattern" + }, + { + "id" : "minecraft:mojang_banner_pattern" + }, + { + "id" : "minecraft:field_masoned_banner_pattern" + }, + { + "id" : "minecraft:bordure_indented_banner_pattern" + }, + { + "id" : "minecraft:piglin_banner_pattern" + }, + { + "id" : "minecraft:globe_banner_pattern" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_star", + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 8, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 7, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 15, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 12, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 14, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 1, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 4, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 5, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 13, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 9, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 3, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 11, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 10, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 2, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 6, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id" : "minecraft:chain" + }, + { + "id" : "minecraft:target", + "blockRuntimeId" : 6392 + }, + { + "id" : "minecraft:lodestone_compass" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json new file mode 100644 index 000000000..00be1af06 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_20.json @@ -0,0 +1,4530 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 379 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 642 + }, + { + "name" : "minecraft:acacia_door", + "id" : 556 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 579 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:acacia_wall_sign", + "id" : -191 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:agent_spawn_egg", + "id" : 487 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 631 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 624 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:armor_stand", + "id" : 552 + }, + { + "name" : "minecraft:arrow", + "id" : 301 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 369 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 500 + }, + { + "name" : "minecraft:azalea", + "id" : -337 + }, + { + "name" : "minecraft:azalea_leaves", + "id" : -324 + }, + { + "name" : "minecraft:azalea_leaves_flowered", + "id" : -325 + }, + { + "name" : "minecraft:baked_potato", + "id" : 281 + }, + { + "name" : "minecraft:balloon", + "id" : 598 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:banner", + "id" : 567 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 651 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 418 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 494 + }, + { + "name" : "minecraft:beef", + "id" : 273 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:beetroot", + "id" : 285 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 295 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 286 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:big_dripleaf", + "id" : -323 + }, + { + "name" : "minecraft:birch_boat", + "id" : 376 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 639 + }, + { + "name" : "minecraft:birch_door", + "id" : 554 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 577 + }, + { + "name" : "minecraft:birch_stairs", + "id" : 135 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:black_candle", + "id" : -428 + }, + { + "name" : "minecraft:black_candle_cake", + "id" : -445 + }, + { + "name" : "minecraft:black_dye", + "id" : 395 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:blackstone", + "id" : -273 + }, + { + "name" : "minecraft:blackstone_double_slab", + "id" : -283 + }, + { + "name" : "minecraft:blackstone_slab", + "id" : -282 + }, + { + "name" : "minecraft:blackstone_stairs", + "id" : -276 + }, + { + "name" : "minecraft:blackstone_wall", + "id" : -277 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 429 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 423 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:bleach", + "id" : 596 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 399 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:boat", + "id" : 649 + }, + { + "name" : "minecraft:bone", + "id" : 415 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 411 + }, + { + "name" : "minecraft:book", + "id" : 387 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 586 + }, + { + "name" : "minecraft:bow", + "id" : 300 + }, + { + "name" : "minecraft:bowl", + "id" : 321 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 431 + }, + { + "name" : "minecraft:brick", + "id" : 383 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:brown_candle", + "id" : -425 + }, + { + "name" : "minecraft:brown_candle_cake", + "id" : -442 + }, + { + "name" : "minecraft:brown_dye", + "id" : 398 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 360 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 417 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camera", + "id" : 593 + }, + { + "name" : "minecraft:campfire", + "id" : 589 + }, + { + "name" : "minecraft:candle", + "id" : -412 + }, + { + "name" : "minecraft:candle_cake", + "id" : -429 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:carrot", + "id" : 279 + }, + { + "name" : "minecraft:carrot_on_a_stick", + "id" : 517 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:cauldron", + "id" : 432 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 457 + }, + { + "name" : "minecraft:cave_vines", + "id" : -322 + }, + { + "name" : "minecraft:cave_vines_body_with_berries", + "id" : -375 + }, + { + "name" : "minecraft:cave_vines_head_with_berries", + "id" : -376 + }, + { + "name" : "minecraft:chain", + "id" : 619 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 342 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 339 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 341 + }, + { + "name" : "minecraft:charcoal", + "id" : 303 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 389 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 435 + }, + { + "name" : "minecraft:chiseled_deepslate", + "id" : -395 + }, + { + "name" : "minecraft:chiseled_nether_bricks", + "id" : -302 + }, + { + "name" : "minecraft:chiseled_polished_blackstone", + "id" : -279 + }, + { + "name" : "minecraft:chorus_flower", + "id" : 200 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 558 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 384 + }, + { + "name" : "minecraft:client_request_placeholder_block", + "id" : -465 + }, + { + "name" : "minecraft:clock", + "id" : 393 + }, + { + "name" : "minecraft:coal", + "id" : 302 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:cobbled_deepslate", + "id" : -379 + }, + { + "name" : "minecraft:cobbled_deepslate_double_slab", + "id" : -396 + }, + { + "name" : "minecraft:cobbled_deepslate_slab", + "id" : -380 + }, + { + "name" : "minecraft:cobbled_deepslate_stairs", + "id" : -381 + }, + { + "name" : "minecraft:cobbled_deepslate_wall", + "id" : -382 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:cocoa_beans", + "id" : 412 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 364 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 480 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 563 + }, + { + "name" : "minecraft:comparator", + "id" : 522 + }, + { + "name" : "minecraft:compass", + "id" : 391 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 594 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:cooked_beef", + "id" : 274 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 276 + }, + { + "name" : "minecraft:cooked_cod", + "id" : 268 + }, + { + "name" : "minecraft:cooked_mutton", + "id" : 551 + }, + { + "name" : "minecraft:cooked_porkchop", + "id" : 263 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 289 + }, + { + "name" : "minecraft:cooked_salmon", + "id" : 269 + }, + { + "name" : "minecraft:cookie", + "id" : 271 + }, + { + "name" : "minecraft:copper_block", + "id" : -340 + }, + { + "name" : "minecraft:copper_ingot", + "id" : 504 + }, + { + "name" : "minecraft:copper_ore", + "id" : -311 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:cow_spawn_egg", + "id" : 436 + }, + { + "name" : "minecraft:cracked_deepslate_bricks", + "id" : -410 + }, + { + "name" : "minecraft:cracked_deepslate_tiles", + "id" : -409 + }, + { + "name" : "minecraft:cracked_nether_bricks", + "id" : -303 + }, + { + "name" : "minecraft:cracked_polished_blackstone_bricks", + "id" : -280 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, + { + "name" : "minecraft:creeper_banner_pattern", + "id" : 582 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 616 + }, + { + "name" : "minecraft:crimson_double_slab", + "id" : -266 + }, + { + "name" : "minecraft:crimson_fence", + "id" : -256 + }, + { + "name" : "minecraft:crimson_fence_gate", + "id" : -258 + }, + { + "name" : "minecraft:crimson_fungus", + "id" : -228 + }, + { + "name" : "minecraft:crimson_hyphae", + "id" : -299 + }, + { + "name" : "minecraft:crimson_nylium", + "id" : -232 + }, + { + "name" : "minecraft:crimson_planks", + "id" : -242 + }, + { + "name" : "minecraft:crimson_pressure_plate", + "id" : -262 + }, + { + "name" : "minecraft:crimson_roots", + "id" : -223 + }, + { + "name" : "minecraft:crimson_sign", + "id" : 614 + }, + { + "name" : "minecraft:crimson_slab", + "id" : -264 + }, + { + "name" : "minecraft:crimson_stairs", + "id" : -254 + }, + { + "name" : "minecraft:crimson_standing_sign", + "id" : -250 + }, + { + "name" : "minecraft:crimson_stem", + "id" : -225 + }, + { + "name" : "minecraft:crimson_trapdoor", + "id" : -246 + }, + { + "name" : "minecraft:crimson_wall_sign", + "id" : -252 + }, + { + "name" : "minecraft:crossbow", + "id" : 575 + }, + { + "name" : "minecraft:crying_obsidian", + "id" : -289 + }, + { + "name" : "minecraft:cut_copper", + "id" : -347 + }, + { + "name" : "minecraft:cut_copper_slab", + "id" : -361 + }, + { + "name" : "minecraft:cut_copper_stairs", + "id" : -354 + }, + { + "name" : "minecraft:cyan_candle", + "id" : -422 + }, + { + "name" : "minecraft:cyan_candle_cake", + "id" : -439 + }, + { + "name" : "minecraft:cyan_dye", + "id" : 401 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 380 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 643 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 557 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 580 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:daylight_detector_inverted", + "id" : 178 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:deepslate", + "id" : -378 + }, + { + "name" : "minecraft:deepslate_brick_double_slab", + "id" : -399 + }, + { + "name" : "minecraft:deepslate_brick_slab", + "id" : -392 + }, + { + "name" : "minecraft:deepslate_brick_stairs", + "id" : -393 + }, + { + "name" : "minecraft:deepslate_brick_wall", + "id" : -394 + }, + { + "name" : "minecraft:deepslate_bricks", + "id" : -391 + }, + { + "name" : "minecraft:deepslate_coal_ore", + "id" : -406 + }, + { + "name" : "minecraft:deepslate_copper_ore", + "id" : -408 + }, + { + "name" : "minecraft:deepslate_diamond_ore", + "id" : -405 + }, + { + "name" : "minecraft:deepslate_emerald_ore", + "id" : -407 + }, + { + "name" : "minecraft:deepslate_gold_ore", + "id" : -402 + }, + { + "name" : "minecraft:deepslate_iron_ore", + "id" : -401 + }, + { + "name" : "minecraft:deepslate_lapis_ore", + "id" : -400 + }, + { + "name" : "minecraft:deepslate_redstone_ore", + "id" : -403 + }, + { + "name" : "minecraft:deepslate_tile_double_slab", + "id" : -398 + }, + { + "name" : "minecraft:deepslate_tile_slab", + "id" : -388 + }, + { + "name" : "minecraft:deepslate_tile_stairs", + "id" : -389 + }, + { + "name" : "minecraft:deepslate_tile_wall", + "id" : -390 + }, + { + "name" : "minecraft:deepslate_tiles", + "id" : -387 + }, + { + "name" : "minecraft:deny", + "id" : 211 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:diamond", + "id" : 304 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 350 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 348 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 347 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 332 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 533 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 349 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 318 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 317 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 316 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 637 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 465 + }, + { + "name" : "minecraft:double_cut_copper_slab", + "id" : -368 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:double_stone_block_slab", + "id" : 43 + }, + { + "name" : "minecraft:double_stone_block_slab2", + "id" : 181 + }, + { + "name" : "minecraft:double_stone_block_slab3", + "id" : -167 + }, + { + "name" : "minecraft:double_stone_block_slab4", + "id" : -168 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 560 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:dried_kelp", + "id" : 270 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:dripstone_block", + "id" : -317 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:drowned_spawn_egg", + "id" : 483 + }, + { + "name" : "minecraft:dye", + "id" : 650 + }, + { + "name" : "minecraft:echo_shard", + "id" : 647 + }, + { + "name" : "minecraft:egg", + "id" : 390 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 471 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_1", + "id" : -12 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:element_104", + "id" : -115 + }, + { + "name" : "minecraft:element_105", + "id" : -116 + }, + { + "name" : "minecraft:element_106", + "id" : -117 + }, + { + "name" : "minecraft:element_107", + "id" : -118 + }, + { + "name" : "minecraft:element_108", + "id" : -119 + }, + { + "name" : "minecraft:element_109", + "id" : -120 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:element_112", + "id" : -123 + }, + { + "name" : "minecraft:element_113", + "id" : -124 + }, + { + "name" : "minecraft:element_114", + "id" : -125 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:element_116", + "id" : -127 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:element_118", + "id" : -129 + }, + { + "name" : "minecraft:element_12", + "id" : -23 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:element_14", + "id" : -25 + }, + { + "name" : "minecraft:element_15", + "id" : -26 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:element_18", + "id" : -29 + }, + { + "name" : "minecraft:element_19", + "id" : -30 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:element_20", + "id" : -31 + }, + { + "name" : "minecraft:element_21", + "id" : -32 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:element_25", + "id" : -36 + }, + { + "name" : "minecraft:element_26", + "id" : -37 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:element_28", + "id" : -39 + }, + { + "name" : "minecraft:element_29", + "id" : -40 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:element_33", + "id" : -44 + }, + { + "name" : "minecraft:element_34", + "id" : -45 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:element_36", + "id" : -47 + }, + { + "name" : "minecraft:element_37", + "id" : -48 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:element_39", + "id" : -50 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:element_40", + "id" : -51 + }, + { + "name" : "minecraft:element_41", + "id" : -52 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:element_45", + "id" : -56 + }, + { + "name" : "minecraft:element_46", + "id" : -57 + }, + { + "name" : "minecraft:element_47", + "id" : -58 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:element_54", + "id" : -65 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:element_56", + "id" : -67 + }, + { + "name" : "minecraft:element_57", + "id" : -68 + }, + { + "name" : "minecraft:element_58", + "id" : -69 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_60", + "id" : -71 + }, + { + "name" : "minecraft:element_61", + "id" : -72 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:element_64", + "id" : -75 + }, + { + "name" : "minecraft:element_65", + "id" : -76 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:element_67", + "id" : -78 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, + { + "name" : "minecraft:element_70", + "id" : -81 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:element_72", + "id" : -83 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:element_76", + "id" : -87 + }, + { + "name" : "minecraft:element_77", + "id" : -88 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:element_79", + "id" : -90 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_80", + "id" : -91 + }, + { + "name" : "minecraft:element_81", + "id" : -92 + }, + { + "name" : "minecraft:element_82", + "id" : -93 + }, + { + "name" : "minecraft:element_83", + "id" : -94 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:element_89", + "id" : -100 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:element_91", + "id" : -102 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:element_94", + "id" : -105 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:element_96", + "id" : -107 + }, + { + "name" : "minecraft:element_97", + "id" : -108 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:element_99", + "id" : -110 + }, + { + "name" : "minecraft:elytra", + "id" : 564 + }, + { + "name" : "minecraft:emerald", + "id" : 512 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 515 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 521 + }, + { + "name" : "minecraft:enchanted_golden_apple", + "id" : 259 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:end_bricks", + "id" : 206 + }, + { + "name" : "minecraft:end_crystal", + "id" : 653 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:ender_eye", + "id" : 433 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 422 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 508 + }, + { + "name" : "minecraft:exposed_copper", + "id" : -341 + }, + { + "name" : "minecraft:exposed_cut_copper", + "id" : -348 + }, + { + "name" : "minecraft:exposed_cut_copper_slab", + "id" : -362 + }, + { + "name" : "minecraft:exposed_cut_copper_stairs", + "id" : -355 + }, + { + "name" : "minecraft:exposed_double_cut_copper_slab", + "id" : -369 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:feather", + "id" : 327 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 428 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 585 + }, + { + "name" : "minecraft:filled_map", + "id" : 420 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 509 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 519 + }, + { + "name" : "minecraft:firework_star", + "id" : 520 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 392 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 356 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 299 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 581 + }, + { + "name" : "minecraft:flower_pot", + "id" : 514 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:frame", + "id" : 513 + }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 628 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 424 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 427 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 434 + }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 588 + }, + { + "name" : "minecraft:glow_berries", + "id" : 654 + }, + { + "name" : "minecraft:glow_frame", + "id" : 623 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 503 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:glow_stick", + "id" : 601 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 394 + }, + { + "name" : "minecraft:goat_horn", + "id" : 627 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 306 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 425 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 325 + }, + { + "name" : "minecraft:golden_boots", + "id" : 354 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 352 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 351 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 333 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 532 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 353 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 324 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 323 + }, + { + "name" : "minecraft:golden_sword", + "id" : 322 + }, + { + "name" : "minecraft:granite_stairs", + "id" : -169 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:grass_path", + "id" : 198 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:gray_candle", + "id" : -420 + }, + { + "name" : "minecraft:gray_candle_cake", + "id" : -437 + }, + { + "name" : "minecraft:gray_dye", + "id" : 403 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 397 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:gunpowder", + "id" : 328 + }, + { + "name" : "minecraft:hanging_roots", + "id" : -319 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:hardened_clay", + "id" : 172 + }, + { + "name" : "minecraft:hay_block", + "id" : 170 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 571 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 592 + }, + { + "name" : "minecraft:honeycomb", + "id" : 591 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 527 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 526 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 595 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 413 + }, + { + "name" : "minecraft:invisible_bedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 298 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 346 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 344 + }, + { + "name" : "minecraft:iron_door", + "id" : 372 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 343 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 331 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 531 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 305 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 345 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 569 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 297 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 296 + }, + { + "name" : "minecraft:iron_sword", + "id" : 307 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:item.birch_door", + "id" : 194 + }, + { + "name" : "minecraft:item.brewing_stand", + "id" : 117 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:item.cauldron", + "id" : 118 + }, + { + "name" : "minecraft:item.chain", + "id" : -286 + }, + { + "name" : "minecraft:item.crimson_door", + "id" : -244 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:item.glow_frame", + "id" : -339 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:item.mangrove_door", + "id" : -493 + }, + { + "name" : "minecraft:item.nether_sprouts", + "id" : -238 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:item.skull", + "id" : 144 + }, + { + "name" : "minecraft:item.soul_campfire", + "id" : -290 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:item.warped_door", + "id" : -245 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:jungle_boat", + "id" : 377 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 640 + }, + { + "name" : "minecraft:jungle_door", + "id" : 555 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 578 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:kelp", + "id" : 382 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 414 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 363 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 547 + }, + { + "name" : "minecraft:leather", + "id" : 381 + }, + { + "name" : "minecraft:leather_boots", + "id" : 338 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 336 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 335 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 530 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 337 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:light_blue_candle", + "id" : -416 + }, + { + "name" : "minecraft:light_blue_candle_cake", + "id" : -433 + }, + { + "name" : "minecraft:light_blue_dye", + "id" : 407 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 402 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:lightning_rod", + "id" : -312 + }, + { + "name" : "minecraft:lime_candle", + "id" : -418 + }, + { + "name" : "minecraft:lime_candle_cake", + "id" : -435 + }, + { + "name" : "minecraft:lime_dye", + "id" : 405 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 562 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:lit_deepslate_redstone_ore", + "id" : -404 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:llama_spawn_egg", + "id" : 473 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 602 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:magenta_candle", + "id" : -415 + }, + { + "name" : "minecraft:magenta_candle_cake", + "id" : -432 + }, + { + "name" : "minecraft:magenta_dye", + "id" : 408 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 430 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:mangrove_boat", + "id" : 635 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 644 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 633 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "name" : "minecraft:mangrove_leaves", + "id" : -472 + }, + { + "name" : "minecraft:mangrove_log", + "id" : -484 + }, + { + "name" : "minecraft:mangrove_planks", + "id" : -486 + }, + { + "name" : "minecraft:mangrove_pressure_plate", + "id" : -490 + }, + { + "name" : "minecraft:mangrove_propagule", + "id" : -474 + }, + { + "name" : "minecraft:mangrove_roots", + "id" : -482 + }, + { + "name" : "minecraft:mangrove_sign", + "id" : 634 + }, + { + "name" : "minecraft:mangrove_slab", + "id" : -489 + }, + { + "name" : "minecraft:mangrove_stairs", + "id" : -488 + }, + { + "name" : "minecraft:mangrove_standing_sign", + "id" : -494 + }, + { + "name" : "minecraft:mangrove_trapdoor", + "id" : -496 + }, + { + "name" : "minecraft:mangrove_wall_sign", + "id" : -495 + }, + { + "name" : "minecraft:mangrove_wood", + "id" : -497 + }, + { + "name" : "minecraft:medicine", + "id" : 599 + }, + { + "name" : "minecraft:medium_amethyst_bud", + "id" : -331 + }, + { + "name" : "minecraft:melon_block", + "id" : 103 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 293 + }, + { + "name" : "minecraft:melon_slice", + "id" : 272 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:milk_bucket", + "id" : 361 + }, + { + "name" : "minecraft:minecart", + "id" : 370 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 584 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 440 + }, + { + "name" : "minecraft:moss_block", + "id" : -320 + }, + { + "name" : "minecraft:moss_carpet", + "id" : -335 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:moving_block", + "id" : 250 + }, + { + "name" : "minecraft:mud", + "id" : -473 + }, + { + "name" : "minecraft:mud_brick_double_slab", + "id" : -479 + }, + { + "name" : "minecraft:mud_brick_slab", + "id" : -478 + }, + { + "name" : "minecraft:mud_brick_stairs", + "id" : -480 + }, + { + "name" : "minecraft:mud_brick_wall", + "id" : -481 + }, + { + "name" : "minecraft:mud_bricks", + "id" : -475 + }, + { + "name" : "minecraft:muddy_mangrove_roots", + "id" : -483 + }, + { + "name" : "minecraft:mule_spawn_egg", + "id" : 466 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 534 + }, + { + "name" : "minecraft:music_disc_5", + "id" : 636 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 536 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 535 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 537 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 538 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 539 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_otherside", + "id" : 626 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 620 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 543 + }, + { + "name" : "minecraft:mutton", + "id" : 550 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 548 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 570 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:nether_gold_ore", + "id" : -288 + }, + { + "name" : "minecraft:nether_sprouts", + "id" : 621 + }, + { + "name" : "minecraft:nether_star", + "id" : 518 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 523 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 607 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 612 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 610 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 609 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 608 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 603 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 611 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 613 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 605 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 604 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:normal_stone_stairs", + "id" : -180 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:npc_spawn_egg", + "id" : 470 + }, + { + "name" : "minecraft:oak_boat", + "id" : 375 + }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 638 + }, + { + "name" : "minecraft:oak_sign", + "id" : 358 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 409 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:oxidized_copper", + "id" : -343 + }, + { + "name" : "minecraft:oxidized_cut_copper", + "id" : -350 + }, + { + "name" : "minecraft:oxidized_cut_copper_slab", + "id" : -364 + }, + { + "name" : "minecraft:oxidized_cut_copper_stairs", + "id" : -357 + }, + { + "name" : "minecraft:oxidized_double_cut_copper_slab", + "id" : -371 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:packed_mud", + "id" : -477 + }, + { + "name" : "minecraft:painting", + "id" : 357 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:paper", + "id" : 386 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 478 + }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 574 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 404 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:piston_arm_collision", + "id" : 34 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:pointed_dripstone", + "id" : -308 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 282 + }, + { + "name" : "minecraft:polar_bear_spawn_egg", + "id" : 472 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:polished_basalt", + "id" : -235 + }, + { + "name" : "minecraft:polished_blackstone", + "id" : -291 + }, + { + "name" : "minecraft:polished_blackstone_brick_double_slab", + "id" : -285 + }, + { + "name" : "minecraft:polished_blackstone_brick_slab", + "id" : -284 + }, + { + "name" : "minecraft:polished_blackstone_brick_stairs", + "id" : -275 + }, + { + "name" : "minecraft:polished_blackstone_brick_wall", + "id" : -278 + }, + { + "name" : "minecraft:polished_blackstone_bricks", + "id" : -274 + }, + { + "name" : "minecraft:polished_blackstone_button", + "id" : -296 + }, + { + "name" : "minecraft:polished_blackstone_double_slab", + "id" : -294 + }, + { + "name" : "minecraft:polished_blackstone_pressure_plate", + "id" : -295 + }, + { + "name" : "minecraft:polished_blackstone_slab", + "id" : -293 + }, + { + "name" : "minecraft:polished_blackstone_stairs", + "id" : -292 + }, + { + "name" : "minecraft:polished_blackstone_wall", + "id" : -297 + }, + { + "name" : "minecraft:polished_deepslate", + "id" : -383 + }, + { + "name" : "minecraft:polished_deepslate_double_slab", + "id" : -397 + }, + { + "name" : "minecraft:polished_deepslate_slab", + "id" : -384 + }, + { + "name" : "minecraft:polished_deepslate_stairs", + "id" : -385 + }, + { + "name" : "minecraft:polished_deepslate_wall", + "id" : -386 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:popped_chorus_fruit", + "id" : 559 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 426 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 368 + }, + { + "name" : "minecraft:powered_comparator", + "id" : 150 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 549 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 565 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 481 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 284 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 292 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:purple_candle", + "id" : -423 + }, + { + "name" : "minecraft:purple_candle_cake", + "id" : -440 + }, + { + "name" : "minecraft:purple_dye", + "id" : 400 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 524 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:quartz_bricks", + "id" : -304 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:rabbit", + "id" : 288 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 528 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 529 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 597 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:raw_copper", + "id" : 507 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 506 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 505 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:recovery_compass", + "id" : 646 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 396 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:redstone", + "id" : 373 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:reinforced_deepslate", + "id" : -466 + }, + { + "name" : "minecraft:repeater", + "id" : 419 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 277 + }, + { + "name" : "minecraft:saddle", + "id" : 371 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 365 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 482 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:sculk", + "id" : -458 + }, + { + "name" : "minecraft:sculk_catalyst", + "id" : -460 + }, + { + "name" : "minecraft:sculk_sensor", + "id" : -307 + }, + { + "name" : "minecraft:sculk_shrieker", + "id" : -461 + }, + { + "name" : "minecraft:sculk_vein", + "id" : -459 + }, + { + "name" : "minecraft:scute", + "id" : 572 + }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:shears", + "id" : 421 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:shield", + "id" : 355 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 566 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skull", + "id" : 516 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 583 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 388 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 445 + }, + { + "name" : "minecraft:small_amethyst_bud", + "id" : -332 + }, + { + "name" : "minecraft:small_dripleaf_block", + "id" : -336 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:smooth_basalt", + "id" : -377 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 374 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 622 + }, + { + "name" : "minecraft:soul_fire", + "id" : -237 + }, + { + "name" : "minecraft:soul_lantern", + "id" : -269 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:soul_soil", + "id" : -236 + }, + { + "name" : "minecraft:soul_torch", + "id" : -268 + }, + { + "name" : "minecraft:sparkler", + "id" : 600 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 652 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:splash_potion", + "id" : 561 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 378 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 641 + }, + { + "name" : "minecraft:spruce_door", + "id" : 553 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 576 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:spruce_trapdoor", + "id" : -149 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:spyglass", + "id" : 625 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 450 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:stick", + "id" : 320 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:sticky_piston_arm_collision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 315 + }, + { + "name" : "minecraft:stone_block_slab", + "id" : 44 + }, + { + "name" : "minecraft:stone_block_slab2", + "id" : 182 + }, + { + "name" : "minecraft:stone_block_slab3", + "id" : -162 + }, + { + "name" : "minecraft:stone_block_slab4", + "id" : -166 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 330 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 314 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 313 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 312 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:string", + "id" : 326 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:stripped_crimson_hyphae", + "id" : -300 + }, + { + "name" : "minecraft:stripped_crimson_stem", + "id" : -240 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:stripped_jungle_log", + "id" : -7 + }, + { + "name" : "minecraft:stripped_mangrove_log", + "id" : -485 + }, + { + "name" : "minecraft:stripped_mangrove_wood", + "id" : -498 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_warped_hyphae", + "id" : -301 + }, + { + "name" : "minecraft:stripped_warped_stem", + "id" : -241 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:sugar", + "id" : 416 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 385 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 590 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 630 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 629 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:tinted_glass", + "id" : -334 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 525 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 568 + }, + { + "name" : "minecraft:trader_llama_spawn_egg", + "id" : 648 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 546 + }, + { + "name" : "minecraft:trip_wire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 366 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 573 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 485 + }, + { + "name" : "minecraft:twisting_vines", + "id" : -287 + }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:unknown", + "id" : -305 + }, + { + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:verdant_froglight", + "id" : -470 + }, + { + "name" : "minecraft:vex_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 632 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 617 + }, + { + "name" : "minecraft:warped_double_slab", + "id" : -267 + }, + { + "name" : "minecraft:warped_fence", + "id" : -257 + }, + { + "name" : "minecraft:warped_fence_gate", + "id" : -259 + }, + { + "name" : "minecraft:warped_fungus", + "id" : -229 + }, + { + "name" : "minecraft:warped_fungus_on_a_stick", + "id" : 618 + }, + { + "name" : "minecraft:warped_hyphae", + "id" : -298 + }, + { + "name" : "minecraft:warped_nylium", + "id" : -233 + }, + { + "name" : "minecraft:warped_planks", + "id" : -243 + }, + { + "name" : "minecraft:warped_pressure_plate", + "id" : -263 + }, + { + "name" : "minecraft:warped_roots", + "id" : -224 + }, + { + "name" : "minecraft:warped_sign", + "id" : 615 + }, + { + "name" : "minecraft:warped_slab", + "id" : -265 + }, + { + "name" : "minecraft:warped_stairs", + "id" : -255 + }, + { + "name" : "minecraft:warped_standing_sign", + "id" : -251 + }, + { + "name" : "minecraft:warped_stem", + "id" : -226 + }, + { + "name" : "minecraft:warped_trapdoor", + "id" : -247 + }, + { + "name" : "minecraft:warped_wall_sign", + "id" : -253 + }, + { + "name" : "minecraft:warped_wart_block", + "id" : -227 + }, + { + "name" : "minecraft:water", + "id" : 9 + }, + { + "name" : "minecraft:water_bucket", + "id" : 362 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:waxed_copper", + "id" : -344 + }, + { + "name" : "minecraft:waxed_cut_copper", + "id" : -351 + }, + { + "name" : "minecraft:waxed_cut_copper_slab", + "id" : -365 + }, + { + "name" : "minecraft:waxed_cut_copper_stairs", + "id" : -358 + }, + { + "name" : "minecraft:waxed_double_cut_copper_slab", + "id" : -372 + }, + { + "name" : "minecraft:waxed_exposed_copper", + "id" : -345 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper", + "id" : -352 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_slab", + "id" : -366 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_stairs", + "id" : -359 + }, + { + "name" : "minecraft:waxed_exposed_double_cut_copper_slab", + "id" : -373 + }, + { + "name" : "minecraft:waxed_oxidized_copper", + "id" : -446 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper", + "id" : -447 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_slab", + "id" : -449 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_stairs", + "id" : -448 + }, + { + "name" : "minecraft:waxed_oxidized_double_cut_copper_slab", + "id" : -450 + }, + { + "name" : "minecraft:waxed_weathered_copper", + "id" : -346 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper", + "id" : -353 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_slab", + "id" : -367 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_stairs", + "id" : -360 + }, + { + "name" : "minecraft:waxed_weathered_double_cut_copper_slab", + "id" : -374 + }, + { + "name" : "minecraft:weathered_copper", + "id" : -342 + }, + { + "name" : "minecraft:weathered_cut_copper", + "id" : -349 + }, + { + "name" : "minecraft:weathered_cut_copper_slab", + "id" : -363 + }, + { + "name" : "minecraft:weathered_cut_copper_stairs", + "id" : -356 + }, + { + "name" : "minecraft:weathered_double_cut_copper_slab", + "id" : -370 + }, + { + "name" : "minecraft:web", + "id" : 30 + }, + { + "name" : "minecraft:weeping_vines", + "id" : -231 + }, + { + "name" : "minecraft:wheat", + "id" : 334 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 410 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 359 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 329 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 310 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 309 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 308 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:writable_book", + "id" : 510 + }, + { + "name" : "minecraft:written_book", + "id" : 511 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 406 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 477 + } +] \ No newline at end of file From 656c8b1a5ebeb990025f9f1bc207b519b85ced19 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 3 Dec 2022 23:59:27 -0500 Subject: [PATCH 268/290] Update mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 5bd26dd73..810a4e817 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 5bd26dd735bd89dd50e5c55a0d022f7c70916300 +Subproject commit 810a4e8174fd9d5b81c5e7d2f3c2f6164565eb9c From 91a2e79bd1aab3e970c4f53ebb57a275372588e1 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 4 Dec 2022 00:30:16 -0500 Subject: [PATCH 269/290] Actually update mappings --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 810a4e817..e8703ccb1 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 810a4e8174fd9d5b81c5e7d2f3c2f6164565eb9c +Subproject commit e8703ccb187f98cd845357395d7b4ecfafbcd864 From f9a52ffc96b6ab1cd10425836bd5c266a0e62b3d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 4 Dec 2022 00:56:43 -0500 Subject: [PATCH 270/290] Add support for SetContentPacket containerId 0 --- .../JavaContainerSetContentTranslator.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java index 619825338..cfe1c404e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetContentTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; +import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; @@ -46,7 +47,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator inventorySize) { + if (i >= inventorySize) { GeyserImpl geyser = session.getGeyser(); geyser.getLogger().warning("ClientboundContainerSetContentPacket sent to " + session.bedrockUsername() + " that exceeds inventory size!"); @@ -54,10 +55,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator 0 || stateId != inventory.getStateId()); @@ -80,4 +75,14 @@ public class JavaContainerSetContentTranslator extends PacketTranslator Date: Sun, 4 Dec 2022 13:34:51 -0500 Subject: [PATCH 271/290] Fix rare dimension switch inconsistencies Fixes #3161 --- .../java/org/geysermc/geyser/session/GeyserSession.java | 1 - .../translator/protocol/java/JavaRespawnTranslator.java | 7 ++----- .../main/java/org/geysermc/geyser/util/DimensionUtils.java | 4 +++- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 17a609fb7..056fa52ee 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -155,7 +155,6 @@ import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.physics.CollisionManager; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index 0f02256d0..45db499f1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -83,11 +83,8 @@ public class JavaRespawnTranslator extends PacketTranslator Date: Sun, 4 Dec 2022 18:12:07 -0500 Subject: [PATCH 272/290] A start on camels and hanging signs --- .../geyser/entity/EntityDefinitions.java | 8 +++ .../type/living/animal/horse/CamelEntity.java | 70 +++++++++++++++++++ .../entity/SignBlockEntityTranslator.java | 3 +- .../BedrockBlockEntityDataTranslator.java | 4 ++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index a552d0875..cad69a117 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -60,6 +60,7 @@ public final class EntityDefinitions { public static final EntityDefinition BEE; public static final EntityDefinition BLAZE; public static final EntityDefinition BOAT; + public static final EntityDefinition CAMEL; public static final EntityDefinition CAT; public static final EntityDefinition CAVE_SPIDER; public static final EntityDefinition CHEST_MINECART; @@ -894,6 +895,13 @@ public final class EntityDefinitions { .type(EntityType.TRADER_LLAMA) .identifier("minecraft:llama") .build(); + CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) + .type(EntityType.CAMEL) + .identifier("minecraft:llama") // todo 1.20 + .height(2.375f).width(1.7f) + .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) + .addTranslator(null) // Last pose change tick + .build(); } EntityDefinition tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java new file mode 100644 index 000000000..408e2ec21 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.entity.type.living.animal.horse; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; + +public class CamelEntity extends AbstractHorseEntity { + + private static final float SITTING_HEIGHT_DIFFERENCE = 1.43F; + + public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + } + + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + this.dirtyMetadata.put(EntityData.VARIANT, 2); // Closest llama colour to camel + } + + @Override + public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { + return "cactus".equals(javaIdentifierStripped); + } + + @Override + protected void setDimensions(Pose pose) { + if (pose == Pose.SITTING) { + setBoundingBoxWidth(definition.height() - SITTING_HEIGHT_DIFFERENCE); + setBoundingBoxWidth(definition.width()); + } else { + super.setDimensions(pose); + } + } + + public void setDashing(BooleanEntityMetadata entityMetadata) { + + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java index bd3f96836..1b4fd6a10 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java @@ -32,7 +32,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.SignUtils; -@BlockEntity(type = BlockEntityType.SIGN) +@BlockEntity(type = {BlockEntityType.SIGN, BlockEntityType.HANGING_SIGN}) public class SignBlockEntityTranslator extends BlockEntityTranslator { /** * Maps a color stored in a sign's Color tag to its ARGB value. @@ -88,6 +88,7 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { signWidth += SignUtils.getCharacterWidth(c); } + // todo 1.20: update for hanging signs (smaller width). Currently OK because bedrock sees hanging signs as normal signs if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) { finalSignLine.append(c); } else { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index 67f0d0d59..d70759ffb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -57,6 +57,10 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator SignUtils.JAVA_CHARACTER_WIDTH_MAX) { // We need to apply some more logic if we went over the character width max From bd5428a2e63cc877473634280876da63b12b1734 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Mon, 5 Dec 2022 14:20:34 -0500 Subject: [PATCH 273/290] Alphabetize the camel --- .../geysermc/geyser/entity/EntityDefinitions.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index cad69a117..b97e23847 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -860,6 +860,13 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags) .addTranslator(null) // UUID of owner .build(); + CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) + .type(EntityType.CAMEL) + .identifier("minecraft:llama") // todo 1.20 + .height(2.375f).width(1.7f) + .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) + .addTranslator(null) // Last pose change tick + .build(); HORSE = EntityDefinition.inherited(HorseEntity::new, abstractHorseEntityBase) .type(EntityType.HORSE) .height(1.6f).width(1.3965f) @@ -895,13 +902,6 @@ public final class EntityDefinitions { .type(EntityType.TRADER_LLAMA) .identifier("minecraft:llama") .build(); - CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) - .type(EntityType.CAMEL) - .identifier("minecraft:llama") // todo 1.20 - .height(2.375f).width(1.7f) - .addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing) - .addTranslator(null) // Last pose change tick - .build(); } EntityDefinition tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase) From f76aa71b5b01d2d0e8f74abf80464dc4a954d98e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:06:40 -0500 Subject: [PATCH 274/290] Point to stable MCProtocolLib version --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 62da6ca89..0a0bccf88 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-SNAPSHOT" +mcprotocollib = "1.19.3-20221206.010348-1" packetlib = "3.0" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" From 0c79732d025ec62738f42b7d67b5ee80f9e11637 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 6 Dec 2022 17:06:10 -0500 Subject: [PATCH 275/290] Add changes from 1.19.3-rc3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0a0bccf88..b18c2db63 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-20221206.010348-1" +mcprotocollib = "1.19.3-20221206.215111-2" packetlib = "3.0" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" From 32829622e719049fd07eff66379ec70c078dbd12 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:07:40 -0500 Subject: [PATCH 276/290] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5051ed04..60cbd94f7 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.50 and Minecraft Java 1.19.1/1.19.2. +### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.50 and Minecraft Java 1.19.3. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From 95ebdb8ebf58ac2a484304b124804373cb9632c1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:59:20 -0500 Subject: [PATCH 277/290] Update BungeeCord version check --- .../geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 1c460f4de..dc7602163 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -76,7 +76,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_19_1"); + ProtocolConstants.class.getField("MINECRAFT_1_19_3"); } catch (NoSuchFieldException e) { getLogger().warning(" / \\"); getLogger().warning(" / \\"); From e7544c0bb44eee07b9da628a99756abeeed5d6db Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 7 Dec 2022 20:09:48 -0500 Subject: [PATCH 278/290] Fix some chat not appearing for Bedrock users --- .../geyser/session/GeyserSession.java | 72 ++----------------- .../java/JavaDisguisedChatTranslator.java | 41 +++++++++++ .../java/JavaPlayerChatTranslator.java | 41 +---------- .../translator/text/MessageTranslator.java | 45 +++++++++++- 4 files changed, 91 insertions(+), 108 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 7a407f6f9..2e3ee4dde 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -58,58 +58,21 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; -import com.github.steveice10.packetlib.event.session.ConnectedEvent; -import com.github.steveice10.packetlib.event.session.DisconnectedEvent; -import com.github.steveice10.packetlib.event.session.PacketErrorEvent; -import com.github.steveice10.packetlib.event.session.PacketSendingEvent; -import com.github.steveice10.packetlib.event.session.SessionAdapter; +import com.github.steveice10.packetlib.event.session.*; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpSession; import com.nukkitx.math.GenericMath; -import com.nukkitx.math.vector.Vector2f; -import com.nukkitx.math.vector.Vector2i; -import com.nukkitx.math.vector.Vector3d; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.math.vector.*; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockServerSession; -import com.nukkitx.protocol.bedrock.data.Ability; -import com.nukkitx.protocol.bedrock.data.AbilityLayer; -import com.nukkitx.protocol.bedrock.data.AttributeData; -import com.nukkitx.protocol.bedrock.data.AuthoritativeMovementMode; -import com.nukkitx.protocol.bedrock.data.ChatRestrictionLevel; -import com.nukkitx.protocol.bedrock.data.GamePublishSetting; -import com.nukkitx.protocol.bedrock.data.GameRuleData; -import com.nukkitx.protocol.bedrock.data.GameType; -import com.nukkitx.protocol.bedrock.data.PlayerPermission; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.data.SyncedPlayerMovementSettings; +import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.AvailableEntityIdentifiersPacket; -import com.nukkitx.protocol.bedrock.packet.BiomeDefinitionListPacket; -import com.nukkitx.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; -import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket; -import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; -import com.nukkitx.protocol.bedrock.packet.CreativeContentPacket; -import com.nukkitx.protocol.bedrock.packet.EmoteListPacket; -import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; -import com.nukkitx.protocol.bedrock.packet.ItemComponentPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet; -import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerFogPacket; -import com.nukkitx.protocol.bedrock.packet.SetTimePacket; -import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; -import com.nukkitx.protocol.bedrock.packet.TransferPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateAbilitiesPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateAdventureSettingsPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; +import com.nukkitx.protocol.bedrock.packet.*; import io.netty.channel.Channel; import io.netty.channel.EventLoop; -import it.unimi.dsi.fastutil.bytes.ByteArrays; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -162,20 +125,7 @@ import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; -import org.geysermc.geyser.session.cache.AdvancementsCache; -import org.geysermc.geyser.session.cache.BookEditCache; -import org.geysermc.geyser.session.cache.ChunkCache; -import org.geysermc.geyser.session.cache.EntityCache; -import org.geysermc.geyser.session.cache.EntityEffectCache; -import org.geysermc.geyser.session.cache.FormCache; -import org.geysermc.geyser.session.cache.LodestoneCache; -import org.geysermc.geyser.session.cache.PistonCache; -import org.geysermc.geyser.session.cache.PreferencesCache; -import org.geysermc.geyser.session.cache.SkullCache; -import org.geysermc.geyser.session.cache.TagCache; -import org.geysermc.geyser.session.cache.TeleportCache; -import org.geysermc.geyser.session.cache.WorldBorder; -import org.geysermc.geyser.session.cache.WorldCache; +import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -191,15 +141,7 @@ import java.net.ConnectException; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -1416,8 +1358,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return clientData.getLanguageCode(); } - // TODO: 1.19.3 int offest and ack'd messages BitSet??? - /** * Sends a chat message to the Java server. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java new file mode 100644 index 000000000..2ad45fe52 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisguisedChatTranslator.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.java; + +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisguisedChatPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.translator.text.MessageTranslator; + +@Translator(packet = ClientboundDisguisedChatPacket.class) +public class JavaDisguisedChatTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundDisguisedChatPacket packet) { + MessageTranslator.handleChatPacket(session, packet.getMessage(), packet.getChatType(), packet.getTargetName(), packet.getName()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java index 4c2d51cb8..e06182b8d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java @@ -26,57 +26,18 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - @Translator(packet = ClientboundPlayerChatPacket.class) public class JavaPlayerChatTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) { - TextPacket textPacket = new TextPacket(); - textPacket.setPlatformChatId(""); - textPacket.setSourceName(""); - textPacket.setXuid(session.getAuthData().xuid()); - textPacket.setType(TextPacket.Type.CHAT); - - textPacket.setNeedsTranslation(false); Component message = packet.getUnsignedContent() == null ? Component.text(packet.getContent()) : packet.getUnsignedContent(); - - TextDecoration decoration = session.getChatTypes().get(packet.getChatType()); - if (decoration != null) { - // As of 1.19 - do this to apply all the styling for signed messages - // Though, Bedrock cannot care about the signed stuff. - TranslatableComponent.Builder withDecoration = Component.translatable() - .key(decoration.translationKey()) - .style(decoration.style()); - Set parameters = decoration.parameters(); - List args = new ArrayList<>(3); - if (parameters.contains(TextDecoration.Parameter.TARGET)) { - args.add(packet.getTargetName()); - } - if (parameters.contains(TextDecoration.Parameter.SENDER)) { - args.add(packet.getName()); - } - if (parameters.contains(TextDecoration.Parameter.CONTENT)) { - args.add(message); - } - withDecoration.args(args); - textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale())); - } else { - textPacket.setMessage(MessageTranslator.convertMessage(message, session.locale())); - } - - session.sendUpstreamPacket(textPacket); + MessageTranslator.handleChatPacket(session, message, packet.getChatType(), packet.getTargetName(), packet.getName()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java index 1b267823a..3d5f5fe0f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java @@ -27,7 +27,9 @@ package org.geysermc.geyser.translator.text; import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; +import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @@ -36,8 +38,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.*; -import java.util.EnumMap; -import java.util.Map; +import java.util.*; public class MessageTranslator { // These are used for handling the translations of the messages @@ -250,6 +251,46 @@ public class MessageTranslator { return PlainTextComponentSerializer.plainText().serialize(messageComponent); } + public static void handleChatPacket(GeyserSession session, Component message, int chatType, Component targetName, Component sender) { + TextPacket textPacket = new TextPacket(); + textPacket.setPlatformChatId(""); + textPacket.setSourceName(""); + textPacket.setXuid(session.getAuthData().xuid()); + textPacket.setType(TextPacket.Type.CHAT); + + textPacket.setNeedsTranslation(false); + + TextDecoration decoration = session.getChatTypes().get(chatType); + if (decoration != null) { + // As of 1.19 - do this to apply all the styling for signed messages + // Though, Bedrock cannot care about the signed stuff. + TranslatableComponent.Builder withDecoration = Component.translatable() + .key(decoration.translationKey()) + .style(decoration.style()); + Set parameters = decoration.parameters(); + List args = new ArrayList<>(3); + if (parameters.contains(TextDecoration.Parameter.TARGET)) { + args.add(targetName); + } + if (parameters.contains(TextDecoration.Parameter.SENDER)) { + args.add(sender); + } + if (parameters.contains(TextDecoration.Parameter.CONTENT)) { + args.add(message); + } + withDecoration.args(args); + textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale())); + } else { + session.getGeyser().getLogger().debug("Likely illegal chat type detection found."); + if (session.getGeyser().getConfig().isDebugMode()) { + Thread.dumpStack(); + } + textPacket.setMessage(MessageTranslator.convertMessage(message, session.locale())); + } + + session.sendUpstreamPacket(textPacket); + } + /** * Convert a team color to a chat color * From 57e34372d8e408835a34d3c0ba7d2ab18d693400 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 7 Dec 2022 22:54:43 -0500 Subject: [PATCH 279/290] Update MCProtocolLib to potentially fix respawn issues --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b18c2db63..d44f8e24a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-20221206.215111-2" +mcprotocollib = "1.19.3-20221208.034912-3" packetlib = "3.0" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" From 247edc6665ce954220288fbcfcddfa9b5a6b88b6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Thu, 8 Dec 2022 21:31:45 -0500 Subject: [PATCH 280/290] Don't say that 1.19.2 is supported (#3443) --- .../src/main/java/org/geysermc/geyser/network/GameProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index e85dc689d..2e080c4dd 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -110,7 +110,7 @@ public final class GameProtocol { * @return the supported Minecraft: Java Edition version names */ public static List getJavaVersions() { - return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion(), "1.19.2"); + return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion()); } /** From 6876a90c3b7337f9d340a2c588e1f04be4d53925 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 9 Dec 2022 13:39:24 -0500 Subject: [PATCH 281/290] Lower size of BiomeDefinitionsPacket --- .../main/java/org/geysermc/geyser/registry/Registries.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 2c1c51baf..866cbd291 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -181,12 +181,15 @@ public final class Registries { POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new); ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new); - // TEMPORARY FIX TO MAKE OLD BIOMES NBT WORK WITH 1.19.30 + // Remove unneeded client generation data from NbtMapBuilder NbtMapBuilder biomesNbt = NbtMap.builder(); for (Map.Entry entry : BIOMES_NBT.get().entrySet()) { String key = entry.getKey(); NbtMapBuilder value = ((NbtMap) entry.getValue()).toBuilder(); - value.put("name_hash", key); + value.remove("minecraft:consolidated_features"); + value.remove("minecraft:multinoise_generation_rules"); + value.remove("minecraft:surface_material_adjustments"); + value.remove( "minecraft:surface_parameters"); biomesNbt.put(key, value.build()); } BIOMES_NBT.set(biomesNbt.build()); From 2d63f09e1674f78868118f1b1c16451710448082 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sun, 11 Dec 2022 00:01:36 -0500 Subject: [PATCH 282/290] Check if spawner contains entity type (#3450) --- .../entity/SpawnerBlockEntityTranslator.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 3d11d5ced..2a4711e26 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.geyser.entity.EntityDefinition; @@ -68,16 +69,18 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { CompoundTag spawnData = tag.get("SpawnData"); if (spawnData != null) { - String entityID = (String) ((CompoundTag) spawnData.get("entity")) - .get("id") - .getValue(); - builder.put("EntityIdentifier", entityID); + StringTag idTag = ((CompoundTag) spawnData.get("entity")).get("id"); + if (idTag != null) { + // As of 1.19.3, spawners can be empty + String entityId = idTag.getValue(); + builder.put("EntityIdentifier", entityId); - EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityID); - if (definition != null) { - builder.put("DisplayEntityWidth", definition.width()); - builder.put("DisplayEntityHeight", definition.height()); - builder.put("DisplayEntityScale", 1.0f); + EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityId); + if (definition != null) { + builder.put("DisplayEntityWidth", definition.width()); + builder.put("DisplayEntityHeight", definition.height()); + builder.put("DisplayEntityScale", 1.0f); + } } } From b27b1c86bdbd6da510ca714a6b85d88c2f7c1704 Mon Sep 17 00:00:00 2001 From: Kas-tle <26531652+Kas-tle@users.noreply.github.com> Date: Sun, 11 Dec 2022 10:15:49 -0800 Subject: [PATCH 283/290] Makes bows, crossbows, tridents, projectiles, and lighters registered as custom items function properly (#3420) Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com> --- .../CustomItemRegistryPopulator.java | 56 +++++++++++++++++++ .../registry/type/GeyserMappingItem.java | 2 + core/src/main/resources/mappings | 2 +- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 0e40f9c43..e32030db6 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -128,6 +128,29 @@ public class CustomItemRegistryPopulator { computeBlockItemProperties(mapping.getBedrockIdentifier(), componentBuilder); } + if (mapping.isEdible()) { + computeConsumableProperties(itemProperties, componentBuilder, 1, false); + } + + if (mapping.isEntityPlacer()) { + computeEntityPlacerProperties(componentBuilder); + } + + switch (mapping.getBedrockIdentifier()) { + case "minecraft:fire_charge", "minecraft:flint_and_steel" -> { + computeBlockItemProperties("minecraft:fire", componentBuilder); + } + case "minecraft:bow", "minecraft:crossbow", "minecraft:trident" -> { + computeChargeableProperties(itemProperties, componentBuilder); + } + case "minecraft:honey_bottle", "minecraft:milk_bucket", "minecraft:potion" -> { + computeConsumableProperties(itemProperties, componentBuilder, 2, true); + } + case "minecraft:experience_bottle", "minecraft:egg", "minecraft:ender_pearl", "minecraft:ender_eye", "minecraft:lingering_potion", "minecraft:snowball", "minecraft:splash_potion" -> { + computeThrowableProperties(componentBuilder); + } + } + computeRenderOffsets(false, customItemData, componentBuilder); componentBuilder.putCompound("item_properties", itemProperties.build()); @@ -273,6 +296,39 @@ public class CustomItemRegistryPopulator { componentBuilder.putCompound("minecraft:block_placer", NbtMap.builder().putString("block", blockItem).build()); } + private static void computeChargeableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) { + // setting high use_duration prevents the consume animation from playing + itemProperties.putInt("use_duration", Integer.MAX_VALUE); + // display item as tool (mainly for crossbow and bow) + itemProperties.putBoolean("hand_equipped", true); + // ensure client moves at slow speed while charging (note: this was calculated by hand as the movement modifer value does not seem to scale linearly) + componentBuilder.putCompound("minecraft:chargeable", NbtMap.builder().putFloat("movement_modifier", 0.35F).build()); + } + + private static void computeConsumableProperties(NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int useAnimation, boolean canAlwaysEat) { + // this is the duration of the use animation in ticks; note that in behavior packs this is set as a float in seconds, but over the network it is an int in ticks + itemProperties.putInt("use_duration", 32); + // this dictates that the item will use the eat or drink animation (in the first person) and play eat or drink sounds + // note that in behavior packs this is set as the string "eat" or "drink", but over the network it as an int, with these values being 1 and 2 respectively + itemProperties.putInt("use_animation", useAnimation); + // this component is required to allow the eat animation to play + componentBuilder.putCompound("minecraft:food", NbtMap.builder().putBoolean("can_always_eat", canAlwaysEat).build()); + } + + private static void computeEntityPlacerProperties(NbtMapBuilder componentBuilder) { + // all items registered that place entities should be given this component to prevent double placement + // it is okay that the entity here does not match the actual one since we control what entity actually spawns + componentBuilder.putCompound("minecraft:entity_placer", NbtMap.builder().putString("entity", "minecraft:minecart").build()); + } + + private static void computeThrowableProperties(NbtMapBuilder componentBuilder) { + // allows item to be thrown when holding down right click (individual presses are required w/o this component) + componentBuilder.putCompound("minecraft:throwable", NbtMap.builder().putBoolean("do_swing_animation", true).build()); + // this must be set to something for the swing animation to play + // it is okay that the projectile here does not match the actual one since we control what entity actually spawns + componentBuilder.putCompound("minecraft:projectile", NbtMap.builder().putString("projectile_entity", "minecraft:snowball").build()); + } + private static void computeRenderOffsets(boolean isHat, CustomItemData customItemData, NbtMapBuilder componentBuilder) { if (isHat) { componentBuilder.remove("minecraft:render_offsets"); diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java index 6c65f1c34..480d1095d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java @@ -48,4 +48,6 @@ public class GeyserMappingItem { @JsonProperty("repair_materials") List repairMaterials; @JsonProperty("has_suspicious_stew_effect") boolean hasSuspiciousStewEffect = false; @JsonProperty("dye_color") int dyeColor = -1; + @JsonProperty("is_edible") boolean edible = false; + @JsonProperty("is_entity_placer") boolean entityPlacer = false; } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e8703ccb1..f9d62b3f7 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e8703ccb187f98cd845357395d7b4ecfafbcd864 +Subproject commit f9d62b3f73db270bd4e0c833b7728b30d29e1369 From 7c26036906f870d739846b8d49f3990c435adc67 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 13 Dec 2022 13:53:28 -0500 Subject: [PATCH 284/290] Update adapters to support 1.19.3 and add biome command completions --- .../GeyserSpigotNativeWorldManager.java | 9 ++ .../geysermc/geyser/level/WorldManager.java | 9 ++ .../geyser/session/GeyserSession.java | 5 + .../protocol/java/JavaCommandsTranslator.java | 94 ++++++++++++++----- .../protocol/java/JavaLoginTranslator.java | 1 + gradle/libs.versions.toml | 2 +- 6 files changed, 98 insertions(+), 22 deletions(-) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index bf9085979..6b5d1ea1e 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -32,6 +32,7 @@ import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; +import org.jetbrains.annotations.Nullable; public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { protected final SpigotWorldAdapter adapter; @@ -49,4 +50,12 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { } return adapter.getBlockAt(player.getWorld(), x, y, z); } + + @Nullable + @Override + public String[] getBiomeIdentifiers(boolean withTags) { + // Biome identifiers will basically always be the same for one server, since you have to re-send the + // ClientboundLoginPacket to change the registry. Therefore, don't bother caching for each player. + return adapter.getBiomeSuggestions(withTags); + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index b3a727d26..e10981f4b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -31,6 +31,7 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import org.geysermc.geyser.session.GeyserSession; +import javax.annotation.Nullable; import java.util.Locale; /** @@ -157,4 +158,12 @@ public abstract class WorldManager { * @return True if the player has the requested permission, false if not */ public abstract boolean hasPermission(GeyserSession session, String permission); + + /** + * Returns a list of biome identifiers available on the server. + */ + @Nullable + public String[] getBiomeIdentifiers(boolean withTags) { + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 2e3ee4dde..8f9bc394a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -296,6 +296,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { */ @Setter private String worldName = null; + /** + * As of Java 1.19.3, the client only uses these for commands. + */ + @Setter + private String[] levels; private boolean sneaking; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 14ff1a51a..11311b63c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -44,6 +44,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import lombok.Getter; import lombok.ToString; import net.kyori.adventure.text.format.NamedTextColor; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.downstream.ServerDefineCommandsEvent; import org.geysermc.geyser.command.GeyserCommandManager; @@ -198,7 +199,7 @@ public class JavaCommandsTranslator extends PacketTranslator= 1) { // Create the root param node and build all the children ParamInfo rootParam = new ParamInfo(commandNode, null); - rootParam.buildChildren(session, allNodes); + rootParam.buildChildren(new CommandBuilderContext(session), allNodes); List treeData = rootParam.getTree(); @@ -211,11 +212,11 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.FILE_PATH; case BOOL -> ENUM_BOOLEAN; case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc - case BLOCK_STATE -> BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.get().keySet().toArray(new String[0]); - case ITEM_STACK -> session.getItemMappings().getItemNames(); + case BLOCK_STATE -> context.getBlockStates(); + case ITEM_STACK -> context.session.getItemMappings().getItemNames(); case COLOR -> VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; - case RESOURCE, RESOURCE_OR_TAG -> { - String resource = ((ResourceProperties) node.getProperties()).getRegistryKey(); - yield switch (resource) { - // minecraft:worldgen/biome is also valid but we currently don't cache biome IDs - case "minecraft:attribute" -> ATTRIBUTES; - case "minecraft:enchantment" -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS; - case "minecraft:entity_type" -> Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0]); - case "minecraft:mob_effect" -> ALL_EFFECT_IDENTIFIERS; - default -> CommandParam.STRING; - }; - } + case RESOURCE -> handleResource(context, ((ResourceProperties) node.getProperties()).getRegistryKey(), false); + case RESOURCE_OR_TAG -> handleResource(context, ((ResourceProperties) node.getProperties()).getRegistryKey(), true); + case DIMENSION -> context.session.getLevels(); + default -> CommandParam.STRING; + }; + } + + private static Object handleResource(CommandBuilderContext context, String resource, boolean tags) { + return switch (resource) { + case "minecraft:attribute" -> ATTRIBUTES; + case "minecraft:enchantment" -> Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS; + case "minecraft:entity_type" -> context.getEntityTypes(); + case "minecraft:mob_effect" -> ALL_EFFECT_IDENTIFIERS; + case "minecraft:worldgen/biome" -> tags ? context.getBiomesWithTags() : context.getBiomes(); default -> CommandParam.STRING; }; } @@ -254,7 +258,55 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Tue, 13 Dec 2022 13:54:40 -0500 Subject: [PATCH 285/290] Indicate 1.19.51 support --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 60cbd94f7..dc6e21b1a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.50 and Minecraft Java 1.19.3. +### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.51 and Minecraft Java 1.19.3. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 2e080c4dd..6b46f8056 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -67,8 +67,12 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.V554_CODEC.toBuilder() .minecraftVersion("1.19.30/1.19.31") .build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.V557_CODEC.toBuilder() + .minecraftVersion("1.19.40/1.19.41") + .build()); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.50/1.19.51") + .build()); } /** From f7375ed7dc9596a66b4413fc765c249e197ae889 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:04:17 -0500 Subject: [PATCH 286/290] Fix chests not animating on open Fixes #3454 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 286430220..55a25a99f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-20221208.034912-3" +mcprotocollib = "1.19.3-20221213.190132-4" packetlib = "3.0" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" From 97bedd39e223ccc155884b9d71b78fab7b240f17 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 16 Dec 2022 14:17:12 -0500 Subject: [PATCH 287/290] Update MCProtocolLib to fix some commands packet decoding --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 55a25a99f..c463130b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-20221213.190132-4" +mcprotocollib = "1.19.3-20221215.055419-5" packetlib = "3.0" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" From 486e2fca1e7afa4123c3fc51bfe455c17210de81 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sat, 17 Dec 2022 12:38:49 -0500 Subject: [PATCH 288/290] Should clean up some crafting transactions a bit --- .../geyser/inventory/click/ClickPlan.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index da72f9f99..bfe5a7d9d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -30,10 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.*; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.SlotType; @@ -124,12 +121,14 @@ public final class ClickPlan { } ItemStack clickedItemStack; - if (!planIter.hasNext() && refresh) { - clickedItemStack = InventoryUtils.REFRESH_ITEM; + if (emulatePost1_16Logic) { + // The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1) + clickedItemStack = simulatedCursor.getItemStack(); } else { - if (emulatePost1_16Logic) { - // The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1) - clickedItemStack = simulatedCursor.getItemStack(); + if (!planIter.hasNext() && refresh) { + // Doesn't have the intended effect with state IDs since this won't cause a complete window refresh + // (It will eventually once state IDs desync, but this causes more problems than not) + clickedItemStack = InventoryUtils.REFRESH_ITEM; } else { if (action.click.actionType == ContainerActionType.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { clickedItemStack = null; From e4dcc07dde581583008c2d7b7a7b6615928a08ea Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 18 Dec 2022 15:49:52 +0100 Subject: [PATCH 289/290] Bump MCProtocolLib and PacketLib --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c463130b1..9b595671e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,8 +8,8 @@ websocket = "1.5.1" protocol = "2.9.15-20221129.204554-2" raknet = "1.6.28-20220125.214016-6" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-20221215.055419-5" -packetlib = "3.0" +mcprotocollib = "1.19.3-20221218.141127-8" +packetlib = "3.0.1" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" junit = "4.13.1" From 3b5984117d7cbd897ed9be8a7d3d9cb3c3f2686a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 18 Dec 2022 22:34:16 -0500 Subject: [PATCH 290/290] Update aux value for polished granite Fixes #3462 --- core/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index f9d62b3f7..677c5b087 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit f9d62b3f73db270bd4e0c833b7728b30d29e1369 +Subproject commit 677c5b0872d2f0c99ad834c0ca49a0ae3b45fde3