├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── move_files.sh ├── settings.gradle.kts └── src └── main ├── kotlin └── de │ └── snowii │ └── extractor │ ├── Extractor.kt │ └── extractors │ ├── Biome.kt │ ├── BiomeDumpTests.kt │ ├── BiomeMixerTest.kt │ ├── Blocks.kt │ ├── Carver.kt │ ├── ChunkDumpTests.kt │ ├── ChunkGenSetting.kt │ ├── ChunkStatus.kt │ ├── DamageTypes.kt │ ├── DensityFunctions.kt │ ├── Entities.kt │ ├── EntityAttributes.kt │ ├── Fluids.kt │ ├── GameEvent.kt │ ├── GameRules.kt │ ├── Items.kt │ ├── MessageType.kt │ ├── MultiNoise.kt │ ├── NoiseParameters.kt │ ├── Packets.kt │ ├── Particles.kt │ ├── PlacedFeatures.kt │ ├── Recipes.kt │ ├── Screens.kt │ ├── Sounds.kt │ ├── StatusEffects.kt │ ├── SyncedRegistries.kt │ ├── Tags.kt │ ├── WorldGenFeatures.kt │ └── non_registry │ ├── EntityPose.kt │ ├── EntityStatuses.kt │ ├── Properties.kt │ ├── ScoreboardDisplaySlot.kt │ ├── SoundCategory.kt │ ├── SpawnEgg.kt │ ├── Translations.kt │ └── WorldEvent.kt └── resources └── fabric.mod.json /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | **/build/ 3 | !src/**/build/ 4 | 5 | # Package Files # 6 | *.jar 7 | *.war 8 | *.nar 9 | *.ear 10 | *.zip 11 | *.tar.gz 12 | *.rar 13 | 14 | # Ignore Gradle GUI config 15 | gradle-app.setting 16 | 17 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 18 | !gradle-wrapper.jar 19 | 20 | # Avoid ignore Gradle wrappper properties 21 | !gradle-wrapper.properties 22 | 23 | # Cache of project 24 | .gradletasknamecache 25 | 26 | # Eclipse Gradle plugin generated files 27 | # Eclipse Core 28 | .project 29 | # JDT-specific (Eclipse Java Development Tools) 30 | .classpath 31 | 32 | # Compiled class file 33 | *.class 34 | 35 | # Log file 36 | *.log 37 | 38 | # BlueJ files 39 | *.ctxt 40 | 41 | # Mobile Tools for Java (J2ME) 42 | .mtj.tmp/ 43 | 44 | .idea 45 | 46 | run/ 47 | 48 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 49 | hs_err_pid* 50 | replay_pid* 51 | 52 | # Kotlin Gradle plugin data, see https://kotlinlang.org/docs/whatsnew20.html#new-directory-for-kotlin-data-in-gradle-projects 53 | .kotlin/ 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Pumpkin MC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | ![Current version)](https://img.shields.io/badge/current_version-1.21.4-blue) 5 | 6 | Extractor is a Fabric mod that extracts Minecraft data (blocks, items, entities, etc.) into JSON files 7 |
8 | 9 | ### Supported Extractors 10 | - [x] Blocks 11 | - [x] Entities 12 | - [x] Items 13 | - [x] Packets 14 | - [x] World Event 15 | - [x] Multi Noise 16 | - [x] Message Type 17 | - [x] Biomes 18 | - [x] Entity Pose 19 | - [x] Attributes 20 | - [x] Sound Category 21 | - [x] Chunk Status 22 | - [x] Game Event 23 | - [x] Game Rule 24 | - [x] Translation (en_us) 25 | - [x] Noise Parameters 26 | - [x] Particles 27 | - [x] Recipes 28 | - [x] Entity Statuses 29 | - [x] Status Effects 30 | - [x] Screens 31 | - [x] Spawn Eggs 32 | - [x] Sounds 33 | - [x] SyncedRegistries 34 | - [x] Tags 35 | - [x] Tests 36 | 37 | ### Running 38 | - Gradle >= 8.12 39 | 40 | 1. Clone the repo 41 | 2. run `./gradlew runServer` or alternatively `./gralde runClient` (Join World) 42 | 3. See JSON Files in the new folder called `pumpkin_extractor_output` 43 | 44 | ### Porting 45 | How to port to a new Minecraft version: 46 | 1. Update versions in `gradle.properties` 47 | 2. Attempt to run and fix any errors that come up 48 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 3 | 4 | plugins { 5 | kotlin("jvm") version "2.1.10" 6 | id("fabric-loom") version "1.10-SNAPSHOT" 7 | id("maven-publish") 8 | } 9 | 10 | version = project.property("mod_version") as String 11 | group = project.property("maven_group") as String 12 | 13 | base { 14 | archivesName.set(project.property("archives_base_name") as String) 15 | } 16 | 17 | val targetJavaVersion = 21 18 | java { 19 | toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) 20 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 21 | // if it is present. 22 | // If you remove this line, sources will not be generated. 23 | withSourcesJar() 24 | } 25 | 26 | loom { 27 | splitEnvironmentSourceSets() 28 | 29 | mods { 30 | register("extractor") { 31 | sourceSet("main") 32 | } 33 | } 34 | } 35 | 36 | repositories { 37 | // Add repositories to retrieve artifacts from in here. 38 | // You should only use this when depending on other mods because 39 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 40 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 41 | // for more information about repositories. 42 | } 43 | 44 | dependencies { 45 | // To change the versions see the gradle.properties file 46 | minecraft("com.mojang:minecraft:${project.property("minecraft_version")}") 47 | mappings("net.fabricmc:yarn:${project.property("yarn_mappings")}:v2") 48 | modImplementation("net.fabricmc:fabric-loader:${project.property("loader_version")}") 49 | modImplementation("net.fabricmc:fabric-language-kotlin:${project.property("kotlin_loader_version")}") 50 | 51 | modImplementation("net.fabricmc.fabric-api:fabric-api:${project.property("fabric_version")}") 52 | 53 | // To allow for reflection 54 | implementation(kotlin("reflect")) 55 | } 56 | 57 | tasks.processResources { 58 | inputs.property("version", project.version) 59 | inputs.property("minecraft_version", project.property("minecraft_version")) 60 | inputs.property("loader_version", project.property("loader_version")) 61 | filteringCharset = "UTF-8" 62 | 63 | filesMatching("fabric.mod.json") { 64 | expand( 65 | "version" to project.version, 66 | "minecraft_version" to project.property("minecraft_version"), 67 | "loader_version" to project.property("loader_version"), 68 | "kotlin_loader_version" to project.property("kotlin_loader_version") 69 | ) 70 | } 71 | } 72 | 73 | tasks.withType().configureEach { 74 | // ensure that the encoding is set to UTF-8, no matter what the system default is 75 | // this fixes some edge cases with special characters not displaying correctly 76 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html 77 | // If Javadoc is generated, this must be specified in that task too. 78 | options.encoding = "UTF-8" 79 | options.release.set(targetJavaVersion) 80 | } 81 | 82 | tasks.withType().configureEach { 83 | compilerOptions.jvmTarget.set(JvmTarget.fromTarget(targetJavaVersion.toString())) 84 | } 85 | 86 | 87 | // configure the maven publication 88 | publishing { 89 | publications { 90 | create("mavenJava") { 91 | artifactId = project.property("archives_base_name") as String 92 | from(components["java"]) 93 | } 94 | } 95 | 96 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 97 | repositories { 98 | // Add repositories to publish to here. 99 | // Notice: This block does NOT have the same function as the block in the top level. 100 | // The repositories here will be used for publishing your artifact, not for 101 | // retrieving dependencies. 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | # Fabric Properties 5 | # check these on https://modmuss50.me/fabric.html 6 | minecraft_version=1.21.5 7 | yarn_mappings=1.21.5+build.1 8 | loader_version=0.16.10 9 | kotlin_loader_version=1.13.2+kotlin.2.1.20 10 | # Mod Properties 11 | mod_version=1.0-SNAPSHOT 12 | maven_group=de.snowii 13 | archives_base_name=extractor 14 | fabric_version=0.119.5+1.21.5 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pumpkin-MC/Extractor/e39ac8b654ba73fc1f445a320548e559a0cdef26/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | org.gradle.wrapper.GradleWrapperMain \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /move_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | PUMPKIN_ROOT="$1" 6 | SCRIPT_ROOT="$(dirname -- "$(readlink -f -- "$0")")" 7 | OUTPUT_DIRECTORY="$SCRIPT_ROOT/run/pumpkin_extractor_output" 8 | 9 | if ! [ -d "$PUMPKIN_ROOT" ]; then 10 | echo "The input must be a valid directory!" 11 | exit 1 12 | fi 13 | 14 | if ! [ -d "$OUTPUT_DIRECTORY" ]; then 15 | echo "Invalid file location directory!" 16 | exit 1 17 | fi 18 | 19 | # Base asset file 20 | OUTPUT_SUBDIR="$PUMPKIN_ROOT/assets" 21 | 22 | if ! [ -d "$OUTPUT_SUBDIR" ]; then 23 | echo "Invalid output location directory!" 24 | exit 1 25 | fi 26 | 27 | declare -a FILES=( 28 | "items.json" 29 | "noise_parameters.json" 30 | "message_type.json" 31 | "en_us.json" 32 | "entity_statuses.json" 33 | "sound_category.json" 34 | "fluids.json" 35 | "tags.json" 36 | "entity_pose.json" 37 | "carver.json" 38 | "game_rules.json" 39 | "game_event.json" 40 | "sounds.json" 41 | "status_effects.json" 42 | "entities.json" 43 | "scoreboard_display_slot.json" 44 | "attributes.json" 45 | "placed_feature.json" 46 | "synced_registries.json" 47 | "spawn_egg.json" 48 | "particles.json" 49 | "multi_noise_biome_tree.json" 50 | "properties.json" 51 | "damage_type.json" 52 | "packets.json" 53 | "screens.json" 54 | "gen_features.json" 55 | "biome.json" 56 | "blocks.json" 57 | "recipes.json" 58 | "chunk_status.json" 59 | "chunk_gen_settings.json" 60 | "density_function.json" 61 | "world_event.json" 62 | ) 63 | 64 | for FILE in "${FILES[@]}"; do 65 | cp "$OUTPUT_DIRECTORY/$FILE" "$OUTPUT_SUBDIR/$FILE" 66 | done 67 | 68 | # World test files 69 | OUTPUT_SUBDIR="$PUMPKIN_ROOT/pumpkin-world/assets" 70 | 71 | if ! [ -d "$OUTPUT_SUBDIR" ]; then 72 | echo "Invalid output location directory!" 73 | exit 1 74 | fi 75 | 76 | declare -a FILES=( 77 | "no_blend_no_beard_only_cell_cache_once_cache_0_0.chunk" 78 | "no_blend_no_beard_only_cell_cache_0_0.chunk" 79 | "biome_no_blend_no_beard_0.json" 80 | "multi_noise_sample_no_blend_no_beard_0_0_0.json" 81 | "no_blend_no_beard_only_cell_cache_interpolated_0_0.chunk" 82 | "no_blend_no_beard_-595_544.chunk" 83 | "no_blend_no_beard_0_0.chunk" 84 | "no_blend_no_beard_surface_badlands_-595_544.chunk" 85 | "no_blend_no_beard_-119_183.chunk" 86 | "no_blend_no_beard_7_4.chunk" 87 | "no_blend_no_beard_surface_frozen_ocean_-119_183.chunk" 88 | "no_blend_no_beard_surface_0_0.chunk" 89 | "multi_noise_biome_source_test.json" 90 | "no_blend_no_beard_only_cell_cache_flat_cache_0_0.chunk" 91 | "density_function_tests.json" 92 | "no_blend_no_beard_13579_-6_11.chunk" 93 | "no_blend_no_beard_surface_13579_-6_11.chunk" 94 | "no_blend_no_beard_13579_-2_15.chunk" 95 | "no_blend_no_beard_surface_13579_-2_15.chunk" 96 | "no_blend_no_beard_surface_13579_-7_9.chunk" 97 | "biome_mixer.json" 98 | ) 99 | 100 | for FILE in "${FILES[@]}"; do 101 | cp "$OUTPUT_DIRECTORY/$FILE" "$OUTPUT_SUBDIR/$FILE" 102 | done 103 | 104 | echo "Files moved." 105 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven("https://maven.fabricmc.net/") { 4 | name = "Fabric" 5 | } 6 | gradlePluginPortal() 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/Extractor.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor 2 | 3 | import com.google.gson.GsonBuilder 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.extractors.* 6 | import de.snowii.extractor.extractors.non_registry.* 7 | import net.fabricmc.api.ModInitializer 8 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents 9 | import net.minecraft.server.MinecraftServer 10 | import org.slf4j.Logger 11 | import org.slf4j.LoggerFactory 12 | import java.io.FileWriter 13 | import java.io.IOException 14 | import java.nio.charset.StandardCharsets 15 | import java.nio.file.Files 16 | import java.nio.file.Path 17 | import java.nio.file.Paths 18 | import kotlin.system.measureTimeMillis 19 | 20 | 21 | class Extractor : ModInitializer { 22 | private val modID: String = "pumpkin_extractor" 23 | private val logger: Logger = LoggerFactory.getLogger(modID) 24 | 25 | override fun onInitialize() { 26 | logger.info("Starting Pumpkin Extractor") 27 | 28 | val extractors = arrayOf( 29 | Sounds(), 30 | Recipes(), 31 | Biome(), 32 | BiomeMixerTest(), 33 | WorldEvent(), 34 | Carver(), 35 | ScoreboardDisplaySlot(), 36 | Particles(), 37 | EntityAttributes(), 38 | ChunkStatus(), 39 | EntityStatuses(), 40 | MessageType(), 41 | StatusEffects(), 42 | SoundCategory(), 43 | EntityPose(), 44 | GameEvent(), 45 | GameRules(), 46 | SpawnEgg(), 47 | SyncedRegistries(), 48 | ChunkGenSetting(), 49 | Packets(), 50 | Screens(), 51 | PlacedFeatures(), 52 | Tags(), 53 | NoiseParameters(), 54 | Entities(), 55 | WorldGenFeatures(), 56 | Items(), 57 | Blocks(), 58 | MultiNoise(), 59 | MultiNoise().Sample(), 60 | ChunkGenSetting(), 61 | Translations(), 62 | DensityFunctions(), 63 | DensityFunctions().Tests(), 64 | DamageTypes(), 65 | Fluids(), 66 | Properties(), 67 | ChunkDumpTests.NoiseDump( 68 | "no_blend_no_beard_0_0.chunk", 69 | 0, 70 | 0, 71 | 0, 72 | arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D") 73 | ), 74 | ChunkDumpTests.NoiseDump( 75 | "no_blend_no_beard_7_4.chunk", 76 | 0, 77 | 7, 78 | 4, 79 | arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D") 80 | ), 81 | ChunkDumpTests.NoiseDump( 82 | "no_blend_no_beard_only_cell_cache_0_0.chunk", 83 | 0, 84 | 0, 85 | 0, 86 | ArrayList() 87 | ), 88 | ChunkDumpTests.NoiseDump( 89 | "no_blend_no_beard_only_cell_cache_flat_cache_0_0.chunk", 90 | 0, 91 | 0, 92 | 0, 93 | arrayListOf("FlatCache") 94 | ), 95 | ChunkDumpTests.NoiseDump( 96 | "no_blend_no_beard_only_cell_cache_interpolated_0_0.chunk", 97 | 0, 98 | 0, 99 | 0, 100 | arrayListOf("Interpolated") 101 | ), 102 | ChunkDumpTests.NoiseDump( 103 | "no_blend_no_beard_only_cell_cache_once_cache_0_0.chunk", 104 | 0, 105 | 0, 106 | 0, 107 | arrayListOf("CacheOnce") 108 | ), 109 | ChunkDumpTests.NoiseDump("no_blend_no_beard_-595_544.chunk", 0, -595, 544, arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D")), 110 | ChunkDumpTests.NoiseDump("no_blend_no_beard_-119_183.chunk", 0, -119, 183, arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D")), 111 | ChunkDumpTests.NoiseDump("no_blend_no_beard_13579_-6_11.chunk", 13579, -6, 11, arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D")), 112 | ChunkDumpTests.NoiseDump("no_blend_no_beard_13579_-2_15.chunk", 13579, -2, 15, arrayListOf("Interpolated", "CacheOnce", "FlatCache", "Cache2D")), 113 | BiomeDumpTests(), 114 | BiomeDumpTests().MultiNoiseBiomeSourceTest(), 115 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_0_0.chunk", 0, 0, 0), 116 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_badlands_-595_544.chunk", 0, -595, 544), 117 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_frozen_ocean_-119_183.chunk", 0, -119, 183), 118 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_13579_-6_11.chunk", 13579, -6, 11), 119 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_13579_-2_15.chunk", 13579, -2, 15), 120 | ChunkDumpTests.SurfaceDump("no_blend_no_beard_surface_13579_-7_9.chunk", 13579, -7, 9) 121 | ) 122 | 123 | val outputDirectory: Path 124 | try { 125 | outputDirectory = Files.createDirectories(Paths.get("pumpkin_extractor_output")) 126 | } catch (e: IOException) { 127 | logger.info("Failed to create output directory.", e) 128 | return 129 | } 130 | 131 | val gson = GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create() 132 | 133 | ServerLifecycleEvents.SERVER_STARTED.register(ServerLifecycleEvents.ServerStarted { server: MinecraftServer -> 134 | val timeInMillis = measureTimeMillis { 135 | for (ext in extractors) { 136 | try { 137 | val out = outputDirectory.resolve(ext.fileName()) 138 | val fileWriter = FileWriter(out.toFile(), StandardCharsets.UTF_8) 139 | gson.toJson(ext.extract(server), fileWriter) 140 | fileWriter.close() 141 | logger.info("Wrote " + out.toAbsolutePath()) 142 | } catch (e: java.lang.Exception) { 143 | logger.error(("Extractor for \"" + ext.fileName()) + "\" failed.", e) 144 | } 145 | } 146 | } 147 | logger.info("Done, took ${timeInMillis}ms") 148 | }) 149 | } 150 | 151 | interface Extractor { 152 | fun fileName(): String 153 | 154 | @Throws(Exception::class) 155 | fun extract(server: MinecraftServer): JsonElement 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Biome.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.world.biome.Biome 11 | 12 | class Biome : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "biome.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val biomeData = JsonObject() 19 | val biomeRegistry = 20 | server.registryManager.getOrThrow(RegistryKeys.BIOME) 21 | for (biome in biomeRegistry) { 22 | val json = Biome.CODEC.encodeStart( 23 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 24 | biome 25 | ).getOrThrow().asJsonObject 26 | json.addProperty("id", biomeRegistry.getRawId(biome)) 27 | biomeData.add( 28 | biomeRegistry.getId(biome)!!.path, json 29 | ) 30 | 31 | } 32 | 33 | return biomeData 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/BiomeDumpTests.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.BuiltinRegistries 8 | import net.minecraft.registry.DynamicRegistryManager 9 | import net.minecraft.registry.Registry 10 | import net.minecraft.registry.RegistryKeys 11 | import net.minecraft.server.MinecraftServer 12 | import net.minecraft.util.math.ChunkPos 13 | import net.minecraft.world.HeightLimitView 14 | import net.minecraft.world.biome.source.* 15 | import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler 16 | import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube 17 | import net.minecraft.world.chunk.ChunkStatus 18 | import net.minecraft.world.chunk.ProtoChunk 19 | import net.minecraft.world.chunk.UpgradeData 20 | import net.minecraft.world.gen.WorldPresets 21 | import net.minecraft.world.gen.chunk.Blender 22 | import net.minecraft.world.gen.chunk.ChunkGeneratorSettings 23 | import net.minecraft.world.gen.chunk.ChunkNoiseSampler 24 | import net.minecraft.world.gen.chunk.GenerationShapeConfig 25 | import net.minecraft.world.gen.densityfunction.DensityFunction.EachApplier 26 | import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos 27 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes 28 | import net.minecraft.world.gen.noise.NoiseConfig 29 | import java.lang.reflect.Field 30 | import java.lang.reflect.Method 31 | 32 | class BiomeDumpTests : Extractor.Extractor { 33 | override fun fileName(): String = "biome_no_blend_no_beard_0.json" 34 | 35 | companion object { 36 | fun createMultiNoiseSampler(config: NoiseConfig, sampler: ChunkNoiseSampler): MultiNoiseSampler { 37 | var createMultiNoiseSampler: Method? = null 38 | for (m: Method in sampler.javaClass.declaredMethods) { 39 | if (m.name == "createMultiNoiseSampler") { 40 | m.trySetAccessible() 41 | createMultiNoiseSampler = m 42 | break 43 | } 44 | } 45 | 46 | val noiseSampler = createMultiNoiseSampler!!.invoke( 47 | sampler, 48 | config.noiseRouter, 49 | listOf() 50 | ) as MultiNoiseSampler 51 | 52 | return noiseSampler 53 | } 54 | } 55 | 56 | override fun extract(server: MinecraftServer): JsonElement { 57 | val topLevelJson = JsonArray() 58 | val seed = 0L 59 | 60 | val biomeRegistry = server.registryManager.getOrThrow(RegistryKeys.BIOME) 61 | 62 | // Overworld shape config 63 | val shape = GenerationShapeConfig(-64, 384, 1, 2) 64 | 65 | val lookup = BuiltinRegistries.createWrapperLookup() 66 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 67 | val noiseParams = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 68 | 69 | val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD) 70 | val settings = ref.value() 71 | val config = NoiseConfig.create(settings, noiseParams, seed) 72 | 73 | 74 | val options = WorldPresets.getDefaultOverworldOptions(lookup) 75 | 76 | var biomeSource: BiomeSource? = null 77 | for (f: Field in options.chunkGenerator.javaClass.fields) { 78 | if (f.name == "biomeSource") { 79 | biomeSource = f.get(options.chunkGenerator) as BiomeSource 80 | } 81 | } 82 | 83 | println(biomeRegistry.javaClass) 84 | println(options.chunkGenerator.javaClass) 85 | 86 | for (x in 5..5) { 87 | for (z in 5..5) { 88 | val biomeData = JsonObject() 89 | biomeData.addProperty("x", x) 90 | biomeData.addProperty("z", z) 91 | 92 | val chunkPos = ChunkPos(x, z) 93 | val chunk = ProtoChunk( 94 | chunkPos, UpgradeData.NO_UPGRADE_DATA, 95 | HeightLimitView.create(options.chunkGenerator.minimumY, options.chunkGenerator.worldHeight), 96 | biomeRegistry, null 97 | ) 98 | 99 | if (chunk.hasBelowZeroRetrogen()) { 100 | throw Exception("Chunk has below zero retrogen") 101 | } 102 | 103 | val testSampler = 104 | ChunkNoiseSampler( 105 | 16 / shape.horizontalCellBlockCount(), config, chunkPos.startX, chunkPos.startZ, 106 | shape, object : DensityFunctionTypes.Beardifying { 107 | override fun maxValue(): Double = 0.0 108 | override fun minValue(): Double = 0.0 109 | override fun sample(pos: NoisePos): Double = 0.0 110 | override fun fill(densities: DoubleArray, applier: EachApplier) { 111 | densities.fill(0.0) 112 | } 113 | }, settings, null, Blender.getNoBlending() 114 | ) 115 | val testNoiseSampler = createMultiNoiseSampler(config, testSampler) 116 | 117 | // We don't have retro gen and we don't want structures 118 | chunk.populateBiomes(biomeSource!!, testNoiseSampler) 119 | chunk.status = ChunkStatus.BIOMES 120 | 121 | val minBiomeY = BiomeCoords.fromBlock(chunk.bottomY) 122 | val maxBiomeY = BiomeCoords.fromBlock(chunk.topYInclusive) 123 | 124 | val data = JsonArray() 125 | for (biomeX in 0..3) { 126 | for (biomeZ in 0..3) { 127 | for (biomeY in minBiomeY..maxBiomeY) { 128 | val chunkData = JsonArray() 129 | 130 | val biome = chunk.getBiomeForNoiseGen(biomeX, biomeY, biomeZ) 131 | // Weird work-around because java 132 | val entry = biomeRegistry.get(biome.key.orElseThrow()) 133 | val id = biomeRegistry.getRawIdOrThrow(entry) 134 | 135 | chunkData.add(biomeX) 136 | chunkData.add(biomeY) 137 | chunkData.add(biomeZ) 138 | chunkData.add(id) 139 | 140 | data.add(chunkData) 141 | } 142 | } 143 | } 144 | 145 | biomeData.add("data", data) 146 | topLevelJson.add(biomeData) 147 | } 148 | } 149 | 150 | return topLevelJson 151 | } 152 | 153 | inner class MultiNoiseBiomeSourceTest : Extractor.Extractor { 154 | override fun fileName(): String = "multi_noise_biome_source_test.json" 155 | 156 | override fun extract(server: MinecraftServer): JsonElement { 157 | val registryManager: DynamicRegistryManager.Immutable = server.registryManager 158 | val multiNoiseRegistry: Registry = 159 | registryManager.getOrThrow(RegistryKeys.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST) 160 | 161 | val overworldBiomeSource = MultiNoiseBiomeSource.create( 162 | multiNoiseRegistry.getOrThrow( 163 | MultiNoiseBiomeSourceParameterLists.OVERWORLD 164 | ) 165 | ) 166 | 167 | val seed = 0L 168 | val chunkPos = ChunkPos(0, 0) 169 | 170 | val lookup = BuiltinRegistries.createWrapperLookup() 171 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 172 | val noiseParams = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 173 | 174 | val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD) 175 | val settings = ref.value() 176 | val config = NoiseConfig.create(settings, noiseParams, seed) 177 | 178 | // Overworld shape config 179 | val shape = GenerationShapeConfig(-64, 384, 1, 2) 180 | val testSampler = 181 | ChunkNoiseSampler( 182 | 16 / shape.horizontalCellBlockCount(), config, chunkPos.startX, chunkPos.startZ, 183 | shape, object : DensityFunctionTypes.Beardifying { 184 | override fun maxValue(): Double = 0.0 185 | override fun minValue(): Double = 0.0 186 | override fun sample(pos: NoisePos): Double = 0.0 187 | override fun fill(densities: DoubleArray, applier: EachApplier) { 188 | densities.fill(0.0) 189 | } 190 | }, settings, null, Blender.getNoBlending() 191 | ) 192 | 193 | val noiseSampler = createMultiNoiseSampler(config, testSampler) 194 | 195 | val topLevelJson = JsonArray() 196 | for (x in -50..50) { 197 | for (y in -20..50) { 198 | for (z in -50..50) { 199 | val biome = overworldBiomeSource.getBiome(x, y, z, noiseSampler) 200 | val id = server.registryManager.getOrThrow(RegistryKeys.BIOME).getRawId(biome.value()) 201 | 202 | val datum = JsonArray() 203 | datum.add(x) 204 | datum.add(y) 205 | datum.add(z) 206 | datum.add(id) 207 | 208 | topLevelJson.add(datum) 209 | } 210 | } 211 | } 212 | return topLevelJson 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/BiomeMixerTest.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.util.math.BlockPos 8 | import net.minecraft.util.math.MathHelper 9 | import net.minecraft.world.biome.source.BiomeAccess 10 | import net.minecraft.world.biome.source.SeedMixer 11 | 12 | class BiomeMixerTest : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "biome_mixer.json" 15 | } 16 | 17 | companion object { 18 | private fun method_38106(l: Long, i: Int, j: Int, k: Int, d: Double, e: Double, f: Double): Double { 19 | var m = SeedMixer.mixSeed(l, i.toLong()) 20 | m = SeedMixer.mixSeed(m, j.toLong()) 21 | m = SeedMixer.mixSeed(m, k.toLong()) 22 | m = SeedMixer.mixSeed(m, i.toLong()) 23 | m = SeedMixer.mixSeed(m, j.toLong()) 24 | m = SeedMixer.mixSeed(m, k.toLong()) 25 | val g = method_38108(m) 26 | m = SeedMixer.mixSeed(m, l) 27 | val h = method_38108(m) 28 | m = SeedMixer.mixSeed(m, l) 29 | val n = method_38108(m) 30 | return MathHelper.square(f + n) + MathHelper.square(e + h) + MathHelper.square(d + g) 31 | } 32 | 33 | private fun method_38108(l: Long): Double { 34 | val d = Math.floorMod(l shr 24, 1024) / 1024.0 35 | return (d - 0.5) * 0.9 36 | } 37 | 38 | fun getBiome(seed: Long, pos: BlockPos): BlockPos { 39 | val i = pos.x - 2 40 | val j = pos.y - 2 41 | val k = pos.z - 2 42 | val l = i shr 2 43 | val m = j shr 2 44 | val n = k shr 2 45 | val d = (i and 3) / 4.0 46 | val e = (j and 3) / 4.0 47 | val f = (k and 3) / 4.0 48 | var o = 0 49 | var g = Double.POSITIVE_INFINITY 50 | 51 | for (p in 0..7) { 52 | val bl = (p and 4) == 0 53 | val bl2 = (p and 2) == 0 54 | val bl3 = (p and 1) == 0 55 | val q = if (bl) l else l + 1 56 | val r = if (bl2) m else m + 1 57 | val s = if (bl3) n else n + 1 58 | val h = if (bl) d else d - 1.0 59 | val t = if (bl2) e else e - 1.0 60 | val u = if (bl3) f else f - 1.0 61 | val v = method_38106(seed, q, r, s, h, t, u) 62 | if (g > v) { 63 | o = p 64 | g = v 65 | } 66 | } 67 | 68 | val px = if ((o and 4) == 0) l else l + 1 69 | val w = if ((o and 2) == 0) m else m + 1 70 | val x = if ((o and 1) == 0) n else n + 1 71 | 72 | return BlockPos(px, w, x) 73 | } 74 | } 75 | 76 | override fun extract(server: MinecraftServer): JsonElement { 77 | val valuesJson = JsonArray() 78 | val startX = (-2).shl(2) 79 | val startZ = (-2).shl(2) 80 | 81 | println(BiomeAccess.hashSeed(-777)) 82 | 83 | for (x in 0..15) { 84 | for (y in -64..256) { 85 | for (z in 0..15) { 86 | val xAbs = startX + x 87 | val zAbs = startZ + z 88 | val result = getBiome(BiomeAccess.hashSeed(-777), BlockPos(xAbs, y, zAbs)) 89 | val point = JsonArray() 90 | point.add(xAbs) 91 | point.add(y) 92 | point.add(zAbs) 93 | point.add(result.x) 94 | point.add(result.y) 95 | point.add(result.z) 96 | 97 | valuesJson.add(point) 98 | } 99 | } 100 | } 101 | 102 | return valuesJson 103 | } 104 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Blocks.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import com.mojang.serialization.JsonOps 7 | import de.snowii.extractor.Extractor 8 | import net.minecraft.block.Block 9 | import net.minecraft.block.ExperienceDroppingBlock 10 | import net.minecraft.block.SideShapeType 11 | import net.minecraft.loot.LootTable 12 | import net.minecraft.registry.Registries 13 | import net.minecraft.registry.RegistryKey 14 | import net.minecraft.registry.RegistryOps 15 | import net.minecraft.server.MinecraftServer 16 | import net.minecraft.util.math.BlockPos 17 | import net.minecraft.util.math.Box 18 | import net.minecraft.util.math.Direction; 19 | import net.minecraft.world.EmptyBlockView 20 | import java.util.* 21 | 22 | class Blocks : Extractor.Extractor { 23 | 24 | companion object { 25 | private const val AIR: Int = 0b00000001 26 | private const val BURNABLE: Int = 0b00000010 27 | private const val TOOL_REQUIRED: Int = 0b00000100 28 | private const val SIDED_TRANSPARENCY: Int = 0b00001000 29 | private const val REPLACEABLE: Int = 0b00010000 30 | private const val IS_LIQUID: Int = 0b00100000 31 | private const val IS_SOLID: Int = 0b01000000 32 | private const val IS_FULL_CUBE: Int = 0b10000000 33 | 34 | private const val DOWN_SIDE_SOLID: Int = 0b00000001; 35 | private const val UP_SIDE_SOLID: Int = 0b00000010; 36 | private const val NORTH_SIDE_SOLID: Int = 0b00000100; 37 | private const val SOUTH_SIDE_SOLID: Int = 0b00001000; 38 | private const val WEST_SIDE_SOLID: Int = 0b00010000; 39 | private const val EAST_SIDE_SOLID: Int = 0b00100000; 40 | private const val DOWN_CENTER_SOLID: Int = 0b01000000; 41 | private const val UP_CENTER_SOLID: Int = 0b10000000; 42 | } 43 | 44 | override fun fileName(): String { 45 | return "blocks.json" 46 | } 47 | 48 | override fun extract(server: MinecraftServer): JsonElement { 49 | val topLevelJson = JsonObject() 50 | 51 | val blocksJson = JsonArray() 52 | 53 | val shapes: LinkedHashMap = LinkedHashMap() 54 | 55 | for (block in Registries.BLOCK) { 56 | val blockJson = JsonObject() 57 | blockJson.addProperty("id", Registries.BLOCK.getRawId(block)) 58 | blockJson.addProperty("name", Registries.BLOCK.getId(block).path) 59 | blockJson.addProperty("translation_key", block.translationKey) 60 | blockJson.addProperty("slipperiness", block.slipperiness) 61 | blockJson.addProperty("velocity_multiplier", block.velocityMultiplier) 62 | blockJson.addProperty("jump_velocity_multiplier", block.jumpVelocityMultiplier) 63 | blockJson.addProperty("hardness", block.hardness) 64 | blockJson.addProperty("blast_resistance", block.blastResistance) 65 | blockJson.addProperty("item_id", Registries.ITEM.getRawId(block.asItem())) 66 | if (block is ExperienceDroppingBlock) { 67 | blockJson.add( 68 | "experience", ExperienceDroppingBlock.CODEC.codec().encodeStart( 69 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 70 | block, 71 | ).getOrThrow() 72 | ) 73 | } 74 | if (block.lootTableKey.isPresent) { 75 | val table = server.reloadableRegistries 76 | .getLootTable(block.lootTableKey.get() as RegistryKey) 77 | blockJson.add( 78 | "loot_table", LootTable::CODEC.get().encodeStart( 79 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 80 | table 81 | ).getOrThrow() 82 | ) 83 | } 84 | val propsJson = JsonArray() 85 | for (prop in block.stateManager.properties) { 86 | // Use the hashcode to map to a property later; the property names are not unique 87 | propsJson.add(prop.hashCode()) 88 | } 89 | blockJson.add("properties", propsJson) 90 | 91 | val statesJson = JsonArray() 92 | for (state in block.stateManager.states) { 93 | val stateJson = JsonObject() 94 | var stateFlags = 0 95 | var sideFlags = 0 96 | 97 | if (state.isAir) stateFlags = stateFlags or AIR 98 | if (state.isBurnable) stateFlags = stateFlags or BURNABLE 99 | if (state.isToolRequired) stateFlags = stateFlags or TOOL_REQUIRED 100 | if (state.hasSidedTransparency()) stateFlags = stateFlags or SIDED_TRANSPARENCY 101 | if (state.isReplaceable) stateFlags = stateFlags or REPLACEABLE 102 | if (state.isLiquid) stateFlags = stateFlags or IS_LIQUID 103 | if (state.isSolid) stateFlags = stateFlags or IS_SOLID 104 | if (state.isFullCube(EmptyBlockView.INSTANCE, BlockPos.ORIGIN)) stateFlags = stateFlags or IS_FULL_CUBE 105 | 106 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.DOWN)) sideFlags = sideFlags or DOWN_SIDE_SOLID 107 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.UP)) sideFlags = sideFlags or UP_SIDE_SOLID 108 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.NORTH)) sideFlags = sideFlags or NORTH_SIDE_SOLID 109 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.SOUTH)) sideFlags = sideFlags or SOUTH_SIDE_SOLID 110 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.WEST)) sideFlags = sideFlags or WEST_SIDE_SOLID 111 | if (state.isSideSolidFullSquare(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.EAST)) sideFlags = sideFlags or EAST_SIDE_SOLID 112 | if (state.isSideSolid(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.DOWN, SideShapeType.CENTER)) sideFlags = sideFlags or DOWN_CENTER_SOLID 113 | if (state.isSideSolid(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, Direction.UP, SideShapeType.CENTER)) sideFlags = sideFlags or UP_CENTER_SOLID 114 | 115 | stateJson.addProperty("id", Block.getRawIdFromState(state)) 116 | stateJson.addProperty("state_flags", stateFlags and 0xFF) 117 | stateJson.addProperty("side_flags", sideFlags and 0xFF) 118 | stateJson.addProperty("instrument", state.instrument.name) 119 | stateJson.addProperty("luminance", state.luminance) 120 | stateJson.addProperty("piston_behavior", state.pistonBehavior.name) 121 | stateJson.addProperty("hardness", state.getHardness(null, null)) 122 | if (state.isOpaque) { 123 | stateJson.addProperty("opacity", state.opacity) 124 | } 125 | 126 | if (block.defaultState == state) { 127 | blockJson.addProperty("default_state_id", Block.getRawIdFromState(state)) 128 | } 129 | 130 | val collisionShapeIdxsJson = JsonArray() 131 | for (box in state.getCollisionShape(EmptyBlockView.INSTANCE, BlockPos.ORIGIN).boundingBoxes) { 132 | val idx = shapes.putIfAbsent(box, shapes.size) 133 | collisionShapeIdxsJson.add(Objects.requireNonNullElseGet(idx) { shapes.size - 1 }) 134 | } 135 | 136 | stateJson.add("collision_shapes", collisionShapeIdxsJson) 137 | 138 | val outlineShapeIdxsJson = JsonArray() 139 | for (box in state.getOutlineShape(EmptyBlockView.INSTANCE, BlockPos.ORIGIN).boundingBoxes) { 140 | val idx = shapes.putIfAbsent(box, shapes.size) 141 | outlineShapeIdxsJson.add(Objects.requireNonNullElseGet(idx) { shapes.size - 1 }) 142 | } 143 | 144 | stateJson.add("outline_shapes", outlineShapeIdxsJson) 145 | 146 | for (blockEntity in Registries.BLOCK_ENTITY_TYPE) { 147 | if (blockEntity.supports(state)) { 148 | stateJson.addProperty("block_entity_type", Registries.BLOCK_ENTITY_TYPE.getRawId(blockEntity)) 149 | } 150 | } 151 | 152 | statesJson.add(stateJson) 153 | } 154 | blockJson.add("states", statesJson) 155 | 156 | blocksJson.add(blockJson) 157 | } 158 | 159 | val blockEntitiesJson = JsonArray() 160 | for (blockEntity in Registries.BLOCK_ENTITY_TYPE) { 161 | blockEntitiesJson.add(Registries.BLOCK_ENTITY_TYPE.getId(blockEntity)!!.path) 162 | } 163 | 164 | val shapesJson = JsonArray() 165 | for (shape in shapes.keys) { 166 | val shapeJson = JsonObject() 167 | val min = JsonArray() 168 | min.add(shape.minX) 169 | min.add(shape.minY) 170 | min.add(shape.minZ) 171 | val max = JsonArray() 172 | max.add(shape.maxX) 173 | max.add(shape.maxY) 174 | max.add(shape.maxZ) 175 | shapeJson.add("min", min) 176 | shapeJson.add("max", max) 177 | shapesJson.add(shapeJson) 178 | } 179 | 180 | topLevelJson.add("block_entity_types", blockEntitiesJson) 181 | topLevelJson.add("shapes", shapesJson) 182 | topLevelJson.add("blocks", blocksJson) 183 | 184 | return topLevelJson 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Carver.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.world.gen.carver.ConfiguredCarver 11 | 12 | class Carver : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "carver.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val finalJson = JsonObject() 19 | val registry = 20 | server.registryManager.getOrThrow(RegistryKeys.CONFIGURED_CARVER) 21 | for (setting in registry) { 22 | finalJson.add( 23 | registry.getId(setting)!!.path, 24 | ConfiguredCarver.CODEC.encodeStart( 25 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 26 | setting 27 | ).getOrThrow() 28 | ) 29 | } 30 | 31 | return finalJson 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/ChunkDumpTests.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.SharedConstants 7 | import net.minecraft.block.Block 8 | import net.minecraft.block.BlockState 9 | import net.minecraft.block.Blocks 10 | import net.minecraft.registry.BuiltinRegistries 11 | import net.minecraft.registry.RegistryKeys 12 | import net.minecraft.server.MinecraftServer 13 | import net.minecraft.util.math.BlockPos 14 | import net.minecraft.util.math.ChunkPos 15 | import net.minecraft.world.HeightLimitView 16 | import net.minecraft.world.Heightmap 17 | import net.minecraft.world.biome.source.BiomeAccess 18 | import net.minecraft.world.biome.source.BiomeSource 19 | import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler 20 | import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube 21 | import net.minecraft.world.chunk.Chunk 22 | import net.minecraft.world.chunk.ChunkStatus 23 | import net.minecraft.world.chunk.ProtoChunk 24 | import net.minecraft.world.chunk.UpgradeData 25 | import net.minecraft.world.gen.HeightContext 26 | import net.minecraft.world.gen.WorldPresets 27 | import net.minecraft.world.gen.chunk.* 28 | import net.minecraft.world.gen.densityfunction.DensityFunction 29 | import net.minecraft.world.gen.densityfunction.DensityFunction.* 30 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes 31 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes.RegistryEntryHolder 32 | import net.minecraft.world.gen.noise.NoiseConfig 33 | import java.lang.reflect.Field 34 | import java.lang.reflect.Method 35 | import kotlin.reflect.KFunction 36 | import kotlin.reflect.full.declaredFunctions 37 | import kotlin.system.exitProcess 38 | 39 | class ChunkDumpTests { 40 | 41 | companion object { 42 | private fun createFluidLevelSampler(settings: ChunkGeneratorSettings): AquiferSampler.FluidLevelSampler { 43 | val fluidLevel = AquiferSampler.FluidLevel(-54, Blocks.LAVA.defaultState) 44 | val i = settings.seaLevel() 45 | val fluidLevel2 = AquiferSampler.FluidLevel(i, settings.defaultFluid()) 46 | return AquiferSampler.FluidLevelSampler { _, y, _ -> if (y < Math.min(-54, i)) fluidLevel else fluidLevel2 } 47 | } 48 | 49 | private fun getIndex(config: GenerationShapeConfig, x: Int, y: Int, z: Int): Int { 50 | if (x < 0 || y < 0 || z < 0) { 51 | println("Bad local pos") 52 | exitProcess(1) 53 | } 54 | return config.height() * 16 * x + 16 * y + z 55 | } 56 | 57 | private fun populateNoise( 58 | settings: ChunkGeneratorSettings, 59 | chunkNoiseSampler: ChunkNoiseSampler, 60 | shapeConfig: GenerationShapeConfig, 61 | chunk: Chunk, 62 | ): Chunk { 63 | var sampleBlockState: KFunction? = null 64 | for (method: KFunction<*> in chunkNoiseSampler::class.declaredFunctions) { 65 | if (method.name == "sampleBlockState") { 66 | sampleBlockState = method as KFunction 67 | } 68 | } 69 | 70 | val heightmap = chunk.getHeightmap(Heightmap.Type.OCEAN_FLOOR_WG) 71 | val heightmap2 = chunk.getHeightmap(Heightmap.Type.WORLD_SURFACE_WG) 72 | val chunkPos = chunk.pos 73 | val i = chunkPos.startX 74 | val j = chunkPos.startZ 75 | val aquiferSampler = chunkNoiseSampler.aquiferSampler 76 | chunkNoiseSampler.sampleStartDensity() 77 | val mutable = BlockPos.Mutable() 78 | val k = shapeConfig.horizontalCellBlockCount() 79 | val l = shapeConfig.verticalCellBlockCount() 80 | val m = 16 / k 81 | val n = 16 / k 82 | 83 | val cellHeight = shapeConfig.height() / l 84 | val minimumCellY = shapeConfig.minimumY() / l 85 | 86 | for (o in 0.. in sampler::class.declaredFunctions) { 161 | if (method.name.equals("sampleBlockState")) { 162 | sampler.sampleStartDensity() 163 | val k = config.horizontalCellBlockCount() 164 | val l = config.verticalCellBlockCount() 165 | 166 | val m = 16 / k 167 | val n = 16 / k 168 | 169 | val cellHeight = config.height() / l 170 | val minimumCellY = config.minimumY() / l 171 | 172 | for (o in 0..) : DensityFunctionVisitor { 213 | override fun apply(densityFunction: DensityFunction?): DensityFunction { 214 | when (densityFunction) { 215 | is DensityFunctionTypes.Wrapper -> { 216 | val name = densityFunction.type().toString() 217 | if (wrappersToKeep.contains(name)) { 218 | return densityFunction 219 | } 220 | return this.apply(densityFunction.wrapped()) 221 | } 222 | 223 | is RegistryEntryHolder -> { 224 | return this.apply(densityFunction.function.value()) 225 | } 226 | 227 | else -> return densityFunction!! 228 | } 229 | } 230 | } 231 | 232 | class WrapperValidateVisitor(private val wrappersToKeep: Iterable) : DensityFunctionVisitor { 233 | override fun apply(densityFunction: DensityFunction?): DensityFunction { 234 | when (densityFunction) { 235 | is DensityFunctionTypes.Wrapper -> { 236 | val name = densityFunction.type().toString() 237 | if (wrappersToKeep.contains(name)) { 238 | return densityFunction 239 | } 240 | throw Exception(name + "is still in the function!") 241 | } 242 | 243 | is RegistryEntryHolder -> { 244 | return this.apply(densityFunction.function.value()) 245 | } 246 | 247 | else -> return densityFunction!! 248 | } 249 | } 250 | } 251 | 252 | // Available: 253 | //Interpolated 254 | //CacheOnce 255 | //FlatCache 256 | //Cache2D 257 | // 258 | //CellCache is only added inside the ChunkSampler itself so it cannot be removed and will always be in the function 259 | private fun removeWrappers(config: NoiseConfig, wrappersToKeep: Iterable) { 260 | val noiseRouter = config.noiseRouter.apply(WrapperRemoverVisitor(wrappersToKeep)) 261 | for (field in config.javaClass.declaredFields) { 262 | if (field.name.equals("noiseRouter")) { 263 | field.trySetAccessible() 264 | field.set(config, noiseRouter) 265 | return 266 | } 267 | } 268 | throw Exception("Failed to replace router") 269 | } 270 | 271 | fun createMultiNoiseSampler(config: NoiseConfig, sampler: ChunkNoiseSampler): MultiNoiseSampler { 272 | var createMultiNoiseSampler: Method? = null 273 | for (m: Method in sampler.javaClass.declaredMethods) { 274 | if (m.name == "createMultiNoiseSampler") { 275 | m.trySetAccessible() 276 | createMultiNoiseSampler = m 277 | break 278 | } 279 | } 280 | 281 | val noiseSampler = createMultiNoiseSampler!!.invoke( 282 | sampler, 283 | config.noiseRouter, 284 | listOf() 285 | ) as MultiNoiseSampler 286 | 287 | return noiseSampler 288 | } 289 | } 290 | 291 | internal class SurfaceDump( 292 | private val filename: String, 293 | private val seed: Long, 294 | private val chunkX: Int, 295 | private val chunkZ: Int, 296 | ) : Extractor.Extractor { 297 | override fun fileName(): String = this.filename 298 | 299 | override fun extract(server: MinecraftServer): JsonElement { 300 | val biomeRegistry = server.registryManager.getOrThrow(RegistryKeys.BIOME) 301 | 302 | val chunkPos = ChunkPos(this.chunkX, this.chunkZ) 303 | 304 | val lookup = BuiltinRegistries.createWrapperLookup() 305 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 306 | val noiseParams = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 307 | 308 | val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD) 309 | val settings = ref.value() 310 | val config = NoiseConfig.create(settings, noiseParams, seed) 311 | 312 | val options = WorldPresets.getDefaultOverworldOptions(lookup) 313 | var biomeSource: BiomeSource? = null 314 | for (f: Field in options.chunkGenerator.javaClass.fields) { 315 | if (f.name == "biomeSource") { 316 | biomeSource = f.get(options.chunkGenerator) as BiomeSource 317 | } 318 | } 319 | 320 | // Overworld shape config 321 | val shape = GenerationShapeConfig(-64, 384, 1, 2) 322 | val testSampler = 323 | ChunkNoiseSampler( 324 | 16 / shape.horizontalCellBlockCount(), config, chunkPos.startX, chunkPos.startZ, 325 | shape, object : DensityFunctionTypes.Beardifying { 326 | override fun maxValue(): Double = 0.0 327 | override fun minValue(): Double = 0.0 328 | override fun sample(pos: NoisePos): Double = 0.0 329 | override fun fill(densities: DoubleArray, applier: EachApplier) { 330 | densities.fill(0.0) 331 | } 332 | }, settings, createFluidLevelSampler(settings), Blender.getNoBlending() 333 | ) 334 | 335 | val chunk = ProtoChunk( 336 | chunkPos, UpgradeData.NO_UPGRADE_DATA, 337 | HeightLimitView.create(options.chunkGenerator.minimumY, options.chunkGenerator.worldHeight), 338 | biomeRegistry, null 339 | ) 340 | 341 | val biomeNoiseSampler = createMultiNoiseSampler(config, testSampler) 342 | chunk.populateBiomes(biomeSource!!, biomeNoiseSampler) 343 | chunk.status = ChunkStatus.BIOMES 344 | 345 | populateNoise(settings, testSampler, shape, chunk) 346 | chunk.status = ChunkStatus.NOISE 347 | 348 | val biomeMixer = BiomeAccess(chunk, BiomeAccess.hashSeed(seed)) 349 | val heightContext = HeightContext(options.chunkGenerator, chunk) 350 | config.surfaceBuilder.buildSurface( 351 | config, 352 | biomeMixer, 353 | biomeRegistry, 354 | settings.usesLegacyRandom, 355 | heightContext, 356 | chunk, 357 | testSampler, 358 | settings.surfaceRule 359 | ) 360 | chunk.status = ChunkStatus.SURFACE 361 | 362 | val result = IntArray(16 * 16 * chunk.height) 363 | for (x in 0..15) { 364 | for (y in chunk.bottomY..chunk.topYInclusive) { 365 | for (z in 0..15) { 366 | val pos = BlockPos(x, y, z) 367 | val blockState = chunk.getBlockState(pos) 368 | val index = getIndex(shape, x, y - chunk.bottomY, z) 369 | result[index] = Block.getRawIdFromState(blockState) 370 | } 371 | } 372 | } 373 | 374 | val topLevelJson = JsonArray() 375 | result.forEach { state -> 376 | topLevelJson.add(state) 377 | } 378 | return topLevelJson 379 | } 380 | } 381 | 382 | internal class NoiseDump( 383 | private val filename: String, 384 | private val seed: Long, 385 | private val chunkX: Int, 386 | private val chunkZ: Int, 387 | private val allowedWrappers: Iterable 388 | ) : Extractor.Extractor { 389 | override fun fileName(): String = this.filename 390 | 391 | // Dumps a chunk to an array of block state ids 392 | override fun extract(server: MinecraftServer): JsonElement { 393 | val topLevelJson = JsonArray() 394 | val chunkPos = ChunkPos(this.chunkX, this.chunkZ) 395 | 396 | val lookup = BuiltinRegistries.createWrapperLookup() 397 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 398 | val noiseParams = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 399 | 400 | val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD) 401 | val settings = ref.value() 402 | val config = NoiseConfig.create(settings, noiseParams, seed) 403 | // Always have cellcache wrappers 404 | removeWrappers(config, this.allowedWrappers) 405 | config.noiseRouter.apply(WrapperValidateVisitor(this.allowedWrappers)) 406 | 407 | // Overworld shape config 408 | val shape = GenerationShapeConfig(-64, 384, 1, 2) 409 | val testSampler = 410 | ChunkNoiseSampler( 411 | 16 / shape.horizontalCellBlockCount(), config, chunkPos.startX, chunkPos.startZ, 412 | shape, object : DensityFunctionTypes.Beardifying { 413 | override fun maxValue(): Double = 0.0 414 | override fun minValue(): Double = 0.0 415 | override fun sample(pos: NoisePos): Double = 0.0 416 | override fun fill(densities: DoubleArray, applier: EachApplier) { 417 | densities.fill(0.0) 418 | } 419 | }, settings, createFluidLevelSampler(settings), Blender.getNoBlending() 420 | ) 421 | 422 | val data = dumpPopulateNoise(chunkPos.startX, chunkPos.startZ, testSampler, shape, settings) 423 | data?.forEach { state -> 424 | topLevelJson.add(state) 425 | } 426 | 427 | return topLevelJson 428 | } 429 | } 430 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/ChunkGenSetting.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.world.gen.chunk.ChunkGeneratorSettings 11 | 12 | class ChunkGenSetting : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "chunk_gen_settings.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val finalJson = JsonObject() 19 | val registry = 20 | server.registryManager.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 21 | for (setting in registry) { 22 | finalJson.add( 23 | registry.getId(setting)!!.path, 24 | ChunkGeneratorSettings.CODEC.encodeStart( 25 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 26 | setting 27 | ).getOrThrow() 28 | ) 29 | } 30 | 31 | return finalJson 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/ChunkStatus.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class ChunkStatus : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "chunk_status.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val statusJson = JsonArray() 16 | for (status in Registries.CHUNK_STATUS) { 17 | statusJson.add( 18 | Registries.CHUNK_STATUS.getId(status).path, 19 | ) 20 | } 21 | 22 | return statusJson 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/DamageTypes.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.entity.damage.DamageType 8 | import net.minecraft.registry.RegistryKeys 9 | import net.minecraft.registry.RegistryOps 10 | import net.minecraft.server.MinecraftServer 11 | 12 | class DamageTypes : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "damage_type.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val damageTypesJson = JsonObject() 19 | val damageTypeRegistry = server.registryManager.getOrThrow(RegistryKeys.DAMAGE_TYPE) 20 | for (type in damageTypeRegistry) { 21 | val json = JsonObject() 22 | json.addProperty("id", damageTypeRegistry.getRawId(type)) 23 | json.add( 24 | "components", 25 | DamageType.CODEC 26 | .encodeStart( 27 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 28 | type 29 | ) 30 | .getOrThrow() 31 | ) 32 | damageTypesJson.add(damageTypeRegistry.getId(type)!!.path, json) 33 | } 34 | 35 | return damageTypesJson 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/DensityFunctions.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import com.google.gson.JsonPrimitive 7 | import de.snowii.extractor.Extractor 8 | import net.minecraft.registry.BuiltinRegistries 9 | import net.minecraft.registry.RegistryKey 10 | import net.minecraft.registry.RegistryKeys 11 | import net.minecraft.server.MinecraftServer 12 | import net.minecraft.util.Identifier 13 | import net.minecraft.util.math.Spline 14 | import net.minecraft.util.math.noise.OctavePerlinNoiseSampler 15 | import net.minecraft.util.math.noise.SimplexNoiseSampler 16 | import net.minecraft.world.gen.densityfunction.DensityFunction 17 | import net.minecraft.world.gen.densityfunction.DensityFunction.Noise 18 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes 19 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes.RegistryEntryHolder 20 | import net.minecraft.world.gen.noise.NoiseRouter 21 | 22 | class DensityFunctions : Extractor.Extractor { 23 | override fun fileName(): String = "density_function.json" 24 | 25 | private fun serializeSpline(spline: Spline<*, *>): JsonObject { 26 | val obj = JsonObject() 27 | 28 | when (spline) { 29 | is Spline.Implementation<*, *> -> { 30 | obj.add("_type", JsonPrimitive("standard")) 31 | 32 | val value = JsonObject() 33 | val functionWrapper = spline.locationFunction() as DensityFunctionTypes.Spline.DensityFunctionWrapper 34 | value.add("locationFunction", serializeFunction(functionWrapper.function.value())) 35 | 36 | val locationArr = JsonArray() 37 | for (location in spline.locations()) { 38 | locationArr.add(JsonPrimitive(location)) 39 | } 40 | value.add("locations", locationArr) 41 | 42 | val valueArr = JsonArray() 43 | for (splineValue in spline.values()) { 44 | valueArr.add(serializeSpline(splineValue)) 45 | } 46 | value.add("values", valueArr) 47 | 48 | val derivativeArr = JsonArray() 49 | for (derivative in spline.derivatives()) { 50 | derivativeArr.add(JsonPrimitive(derivative)) 51 | } 52 | value.add("derivatives", derivativeArr) 53 | 54 | obj.add("value", value) 55 | } 56 | 57 | is Spline.FixedFloatFunction<*, *> -> { 58 | obj.add("_type", JsonPrimitive("fixed")) 59 | 60 | val value = JsonObject() 61 | value.add("value", JsonPrimitive(spline.value())) 62 | 63 | obj.add("value", value) 64 | } 65 | 66 | else -> throw Exception("Unknown spline: $obj (${obj.javaClass})") 67 | } 68 | 69 | return obj 70 | } 71 | 72 | private fun serializeValue(name: String, obj: Any, parent: String): JsonElement { 73 | return when (obj) { 74 | is DensityFunction -> serializeFunction(obj) 75 | is Noise -> JsonPrimitive(obj.noiseData.key.get().value.path) 76 | is Spline<*, *> -> serializeSpline(obj) 77 | is Int -> JsonPrimitive(obj) 78 | is Float -> { 79 | /* 80 | if (obj.isNaN()) { 81 | throw Exception("Bad float ($name) from $parent") 82 | } 83 | */ 84 | JsonPrimitive(obj) 85 | } 86 | 87 | is Double -> { 88 | /* 89 | if (obj.isNaN()) { 90 | throw Exception("Bad double ($name) from $parent") 91 | } 92 | */ 93 | JsonPrimitive(obj) 94 | } 95 | 96 | is Boolean -> JsonPrimitive(obj) 97 | is String -> JsonPrimitive(obj) 98 | is Char -> JsonPrimitive(obj) 99 | is Enum<*> -> JsonPrimitive(obj.name) 100 | else -> throw Exception("Unknown value to serialize: $obj ($name) from $parent") 101 | } 102 | } 103 | 104 | private fun serializeFunction(function: DensityFunction): JsonObject { 105 | val obj = JsonObject() 106 | 107 | if (function is RegistryEntryHolder) { 108 | return serializeFunction(function.function.value()) 109 | } 110 | 111 | obj.add("_class", JsonPrimitive(function.javaClass.simpleName)) 112 | 113 | val value = JsonObject() 114 | for (field in function.javaClass.declaredFields) { 115 | if (field.name.first().isUpperCase()) { 116 | // We only want to serialize the used values 117 | continue 118 | } 119 | 120 | // These are constant 121 | if (function.javaClass.simpleName == "BlendDensity") { 122 | if (field.name == "maxValue") { 123 | continue 124 | } 125 | if (field.name == "minValue") { 126 | continue 127 | } 128 | } 129 | 130 | if (function is DensityFunctionTypes.Spline) { 131 | value.add("minValue", JsonPrimitive(function.minValue())) 132 | value.add("maxValue", JsonPrimitive(function.maxValue())) 133 | } 134 | 135 | // These aren't used 136 | if (field.name.startsWith("field_")) { 137 | continue 138 | } 139 | 140 | field.trySetAccessible() 141 | val fieldValue = field.get(function) 142 | when (fieldValue) { 143 | // SimplexNoiseSampler is initialized with a random value during runtime 144 | is SimplexNoiseSampler -> continue 145 | // OctavePerlinNoiseSampler is initialized with a random value during runtime 146 | is OctavePerlinNoiseSampler -> continue 147 | } 148 | 149 | val serialized = serializeValue(field.name, fieldValue, function.javaClass.simpleName) 150 | value.add(field.name, serialized) 151 | } 152 | 153 | if (!value.isEmpty) { 154 | obj.add("value", value) 155 | } 156 | 157 | return obj 158 | } 159 | 160 | private fun serializeRouter(router: NoiseRouter): JsonObject { 161 | val obj = JsonObject() 162 | 163 | for (field in router.javaClass.declaredFields) { 164 | if (field.name.first().isUpperCase()) { 165 | // CODEC is not a value we want 166 | continue 167 | } 168 | 169 | field.trySetAccessible() 170 | val function = field.get(router) 171 | val serialized = serializeFunction(function as DensityFunction) 172 | obj.add(field.name, serialized) 173 | } 174 | 175 | return obj 176 | } 177 | 178 | override fun extract(server: MinecraftServer): JsonElement { 179 | val topLevelJson = JsonObject() 180 | 181 | val lookup = BuiltinRegistries.createWrapperLookup() 182 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 183 | 184 | wrapper.streamKeys().forEach { key -> 185 | val entry = wrapper.getOrThrow(key) 186 | val settings = entry.value() 187 | 188 | val obj = serializeRouter(settings.noiseRouter) 189 | topLevelJson.add(key.value.path, obj) 190 | } 191 | return topLevelJson 192 | } 193 | 194 | // Dump the building blocks of the density functions to validate proper results 195 | inner class Tests : Extractor.Extractor { 196 | override fun fileName(): String = "density_function_tests.json" 197 | 198 | override fun extract(server: MinecraftServer): JsonElement { 199 | val topLevelJson = JsonObject() 200 | 201 | val functionNames = arrayOf( 202 | "overworld/base_3d_noise", 203 | "overworld/caves/entrances", 204 | "overworld/caves/noodle", 205 | "overworld/caves/pillars", 206 | "overworld/caves/spaghetti_2d", 207 | "overworld/caves/spaghetti_2d_thickness_modulator", 208 | "overworld/caves/spaghetti_roughness_function", 209 | "overworld/offset", 210 | "overworld/depth", 211 | "overworld/factor", 212 | "overworld/sloped_cheese" 213 | ) 214 | 215 | val lookup = BuiltinRegistries.createWrapperLookup() 216 | val functionLookup = lookup.getOrThrow(RegistryKeys.DENSITY_FUNCTION) 217 | for (functionName in functionNames) { 218 | val functionKey = 219 | RegistryKey.of( 220 | RegistryKeys.DENSITY_FUNCTION, 221 | Identifier.ofVanilla(functionName) 222 | ) 223 | val function = functionLookup.getOrThrow(functionKey).value() 224 | topLevelJson.add(functionName, serializeFunction(function)) 225 | } 226 | 227 | return topLevelJson 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Entities.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import com.mojang.serialization.JsonOps 7 | import de.snowii.extractor.Extractor 8 | import net.minecraft.entity.LivingEntity 9 | import net.minecraft.entity.SpawnReason 10 | import net.minecraft.loot.LootTable 11 | import net.minecraft.registry.Registries 12 | import net.minecraft.registry.RegistryKey 13 | import net.minecraft.registry.RegistryOps 14 | import net.minecraft.server.MinecraftServer 15 | 16 | class Entities : Extractor.Extractor { 17 | override fun fileName(): String { 18 | return "entities.json" 19 | } 20 | 21 | override fun extract(server: MinecraftServer): JsonElement { 22 | val entitiesJson = JsonObject() 23 | for (entityType in Registries.ENTITY_TYPE) { 24 | val entityJson = JsonObject() 25 | entityJson.addProperty("id", Registries.ENTITY_TYPE.getRawId(entityType)) 26 | val entity = entityType.create(server.overworld!!, SpawnReason.NATURAL) 27 | if (entity != null) { 28 | if (entity is LivingEntity) { 29 | entityJson.addProperty("max_health", entity.maxHealth) 30 | } 31 | entityJson.addProperty("attackable", entity.isAttackable) 32 | } 33 | entityJson.addProperty("summonable", entityType.isSummonable) 34 | entityJson.addProperty("fire_immune", entityType.isFireImmune) 35 | val dimension = JsonArray() 36 | dimension.add(entityType.width) 37 | dimension.add(entityType.height) 38 | entityJson.add("dimension", dimension) 39 | entityJson.addProperty("eye_height", entityType.dimensions.eyeHeight) 40 | if (entityType.lootTableKey.isPresent) { 41 | val table = server.reloadableRegistries 42 | .getLootTable(entityType.lootTableKey.get() as RegistryKey) 43 | entityJson.add( 44 | "loot_table", LootTable::CODEC.get().encodeStart( 45 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 46 | table 47 | ).getOrThrow() 48 | ) 49 | } 50 | 51 | entitiesJson.add( 52 | Registries.ENTITY_TYPE.getId(entityType).path, entityJson 53 | ) 54 | } 55 | 56 | return entitiesJson 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/EntityAttributes.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class EntityAttributes : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "attributes.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val finalJson = JsonObject() 16 | for (attribute in Registries.ATTRIBUTE) { 17 | finalJson.addProperty( 18 | Registries.ATTRIBUTE.getId(attribute)!!.path, 19 | attribute.defaultValue 20 | ) 21 | } 22 | 23 | return finalJson 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Fluids.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.block.Block 8 | import net.minecraft.registry.Registries 9 | import net.minecraft.server.MinecraftServer 10 | 11 | class Fluids : Extractor.Extractor { 12 | override fun fileName(): String { 13 | return "fluids.json" 14 | } 15 | 16 | override fun extract(server: MinecraftServer): JsonElement { 17 | val topLevelJson = JsonArray() 18 | 19 | for (fluid in Registries.FLUID) { 20 | val fluidJson = JsonObject() 21 | fluidJson.addProperty("id", Registries.FLUID.getRawId(fluid)) 22 | fluidJson.addProperty("name", Registries.FLUID.getId(fluid).path) 23 | 24 | val propsJson = JsonArray() 25 | for (prop in fluid.stateManager.properties) { 26 | val propJson = JsonObject() 27 | 28 | propJson.addProperty("name", prop.name) 29 | 30 | val valuesJson = JsonArray() 31 | for (value in prop.values) { 32 | valuesJson.add(value.toString().lowercase()) 33 | } 34 | propJson.add("values", valuesJson) 35 | 36 | propsJson.add(propJson) 37 | } 38 | fluidJson.add("properties", propsJson) 39 | 40 | val statesJson = JsonArray() 41 | for ((index, state) in fluid.stateManager.states.withIndex()) { 42 | val stateJson = JsonObject() 43 | stateJson.addProperty("height", state.height) 44 | stateJson.addProperty("level", state.level) 45 | stateJson.addProperty("is_empty", state.isEmpty) 46 | stateJson.addProperty("blast_resistance", state.blastResistance) 47 | stateJson.addProperty("block_state_id", Block.getRawIdFromState(state.blockState)) 48 | stateJson.addProperty("is_still", state.isStill) 49 | // TODO: Particle effects 50 | 51 | if (fluid.defaultState == state) { 52 | fluidJson.addProperty("default_state_index", index) 53 | } 54 | 55 | statesJson.add(stateJson) 56 | } 57 | fluidJson.add("states", statesJson) 58 | 59 | topLevelJson.add(fluidJson) 60 | } 61 | 62 | return topLevelJson 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/GameEvent.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.RegistryKeys 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class GameEvent : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "game_event.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val gameEventJson = JsonArray() 16 | val gameEventTypeRegistry = 17 | server.registryManager.getOrThrow(RegistryKeys.GAME_EVENT) 18 | for (event in gameEventTypeRegistry) { 19 | gameEventJson.add( 20 | gameEventTypeRegistry.getId(event)!!.path, 21 | ) 22 | } 23 | 24 | return gameEventJson 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/GameRules.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.resource.featuretoggle.FeatureFlags 7 | import net.minecraft.server.MinecraftServer 8 | import net.minecraft.world.GameRules 9 | 10 | class GameRules : Extractor.Extractor { 11 | override fun fileName(): String { 12 | return "game_rules.json" 13 | } 14 | 15 | override fun extract(server: MinecraftServer): JsonElement { 16 | val gameEventJson = JsonObject() 17 | val rules = GameRules(FeatureFlags::VANILLA_FEATURES.get()) 18 | rules.accept(object : GameRules.Visitor { 19 | override fun ?> visit(key: GameRules.Key, type: GameRules.Type) { 20 | gameEventJson.addProperty(key.name, type.createRule()!!.serialize()) 21 | } 22 | }) 23 | return gameEventJson 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Items.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.component.ComponentMap 8 | import net.minecraft.item.Item 9 | import net.minecraft.registry.Registries 10 | import net.minecraft.registry.RegistryKeys 11 | import net.minecraft.registry.RegistryOps 12 | import net.minecraft.server.MinecraftServer 13 | 14 | 15 | class Items : Extractor.Extractor { 16 | override fun fileName(): String { 17 | return "items.json" 18 | } 19 | 20 | 21 | override fun extract(server: MinecraftServer): JsonElement { 22 | val itemsJson = JsonObject() 23 | 24 | for (item in server.registryManager.getOrThrow(RegistryKeys.ITEM).streamEntries().toList()) { 25 | val itemJson = JsonObject() 26 | val realItem: Item = item.value() 27 | 28 | itemJson.addProperty("id", Registries.ITEM.getRawId(realItem)) 29 | itemJson.add( 30 | "components", 31 | ComponentMap.CODEC.encodeStart( 32 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 33 | realItem.components 34 | ).getOrThrow() 35 | ) 36 | 37 | itemsJson.add(Registries.ITEM.getId(realItem).path, itemJson) 38 | } 39 | return itemsJson 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/MessageType.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.network.message.MessageType 8 | import net.minecraft.registry.RegistryKeys 9 | import net.minecraft.registry.RegistryOps 10 | import net.minecraft.server.MinecraftServer 11 | 12 | class MessageType : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "message_type.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val messagesJson = JsonObject() 19 | val messageTypeRegistry = 20 | server.registryManager.getOrThrow(RegistryKeys.MESSAGE_TYPE) 21 | for (type in messageTypeRegistry) { 22 | val json = JsonObject() 23 | json.addProperty("id", messageTypeRegistry.getRawId(type)) 24 | json.add( 25 | "components", MessageType.CODEC.encodeStart( 26 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), type 27 | ).getOrThrow() 28 | ) 29 | messagesJson.add( 30 | messageTypeRegistry.getId(type)!!.path, 31 | json 32 | ) 33 | } 34 | 35 | return messagesJson 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/MultiNoise.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.BuiltinRegistries 8 | import net.minecraft.registry.DynamicRegistryManager 9 | import net.minecraft.registry.Registry 10 | import net.minecraft.registry.RegistryKeys 11 | import net.minecraft.registry.entry.RegistryEntry 12 | import net.minecraft.server.MinecraftServer 13 | import net.minecraft.util.math.ChunkPos 14 | import net.minecraft.world.biome.Biome 15 | import net.minecraft.world.biome.source.MultiNoiseBiomeSource 16 | import net.minecraft.world.biome.source.MultiNoiseBiomeSourceParameterList 17 | import net.minecraft.world.biome.source.MultiNoiseBiomeSourceParameterLists 18 | import net.minecraft.world.biome.source.util.MultiNoiseUtil 19 | import net.minecraft.world.biome.source.util.MultiNoiseUtil.* 20 | import net.minecraft.world.gen.chunk.Blender 21 | import net.minecraft.world.gen.chunk.ChunkGeneratorSettings 22 | import net.minecraft.world.gen.chunk.ChunkNoiseSampler 23 | import net.minecraft.world.gen.chunk.GenerationShapeConfig 24 | import net.minecraft.world.gen.densityfunction.DensityFunction.EachApplier 25 | import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos 26 | import net.minecraft.world.gen.densityfunction.DensityFunctionTypes 27 | import net.minecraft.world.gen.noise.NoiseConfig 28 | import java.lang.reflect.Field 29 | import java.lang.reflect.Method 30 | import kotlin.reflect.KFunction 31 | import kotlin.reflect.full.declaredFunctions 32 | 33 | /** 34 | * An extractor for MultiNoiseBiomeSourceParameterList that fully serializes NoiseHypercube and ParameterRange data. 35 | */ 36 | class MultiNoise : Extractor.Extractor { 37 | 38 | override fun fileName(): String { 39 | return "multi_noise_biome_tree.json" 40 | } 41 | 42 | fun extract_tree_node(node: Any?): JsonObject { 43 | val json = JsonObject() 44 | for (f: Field in node!!::class.java.fields) { 45 | if (f.name == "parameters") { 46 | f.trySetAccessible() 47 | val parameters = JsonArray() 48 | val ranges = f.get(node) as Array 49 | for (range in ranges) { 50 | val parameter = JsonObject() 51 | parameter.addProperty("min", range.min) 52 | parameter.addProperty("max", range.max) 53 | parameters.add(parameter) 54 | } 55 | json.add("parameters", parameters) 56 | } 57 | if (f.name == "subTree") { 58 | f.trySetAccessible() 59 | val subTree = JsonArray() 60 | val nodes = f.get(node) as Array 61 | for (childNode in nodes) { 62 | subTree.add(extract_tree_node(childNode)) 63 | } 64 | json.add("subTree", subTree) 65 | json.addProperty("_type", "branch") 66 | } 67 | if (f.name == "value") { 68 | f.trySetAccessible() 69 | val value = f.get(node) as RegistryEntry 70 | json.addProperty("biome", value.idAsString) 71 | json.addProperty("_type", "leaf") 72 | } 73 | } 74 | return json 75 | } 76 | 77 | fun extract_search_tree(tree: Any?): JsonObject { 78 | var field: Field? = null 79 | for (f: Field in tree!!::class.java.declaredFields) { 80 | if (f.name == "firstNode") { 81 | f.trySetAccessible() 82 | field = f 83 | } 84 | } 85 | 86 | return extract_tree_node(field!!.get(tree)) 87 | } 88 | 89 | // Only overworld and nether use multi noise sampler for biomes 90 | override fun extract(server: MinecraftServer): JsonElement { 91 | val registryManager: DynamicRegistryManager.Immutable = server.registryManager 92 | val multiNoiseRegistry: Registry = 93 | registryManager.getOrThrow(RegistryKeys.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST) 94 | 95 | val overworldBiomeSource = 96 | MultiNoiseBiomeSource.create(multiNoiseRegistry.getOrThrow(MultiNoiseBiomeSourceParameterLists.OVERWORLD)) 97 | 98 | var method: Method? = null 99 | for (m: Method in overworldBiomeSource::class.java.declaredMethods) { 100 | if (m.name == "getBiomeEntries") { 101 | m.trySetAccessible() 102 | method = m 103 | break 104 | } 105 | } 106 | 107 | val overworldEntries = method!!.invoke(overworldBiomeSource) as MultiNoiseUtil.Entries> 108 | 109 | var field: Field? = null 110 | for (f: Field in overworldEntries::class.java.declaredFields) { 111 | if (f.name == "tree") { 112 | f.trySetAccessible() 113 | field = f 114 | } 115 | } 116 | 117 | val overworld = extract_search_tree(field!!.get(overworldEntries)) 118 | 119 | val netherBiomeSource = MultiNoiseBiomeSource.create(multiNoiseRegistry.getOrThrow(MultiNoiseBiomeSourceParameterLists.NETHER)) 120 | 121 | method = null 122 | for (m: Method in netherBiomeSource::class.java.declaredMethods) { 123 | if (m.name == "getBiomeEntries") { 124 | m.trySetAccessible() 125 | method = m 126 | break 127 | } 128 | } 129 | 130 | val netherEntries = method!!.invoke(netherBiomeSource) as MultiNoiseUtil.Entries> 131 | 132 | field = null 133 | for (f: Field in netherEntries::class.java.declaredFields) { 134 | if (f.name == "tree") { 135 | f.trySetAccessible() 136 | field = f 137 | } 138 | } 139 | 140 | val nether = extract_search_tree(field!!.get(netherEntries)) 141 | 142 | val returnValue = JsonObject() 143 | returnValue.add("overworld", overworld) 144 | returnValue.add("nether", nether) 145 | return returnValue 146 | } 147 | 148 | inner class Sample : Extractor.Extractor { 149 | override fun fileName(): String { 150 | return "multi_noise_sample_no_blend_no_beard_0_0_0.json" 151 | } 152 | 153 | override fun extract(server: MinecraftServer): JsonElement { 154 | val rootJson = JsonArray() 155 | 156 | val seed = 0L 157 | val chunkPos = ChunkPos(0, 0) 158 | 159 | val lookup = BuiltinRegistries.createWrapperLookup() 160 | val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS) 161 | val noiseParams = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 162 | 163 | val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD) 164 | val settings = ref.value() 165 | val config = NoiseConfig.create(settings, noiseParams, seed) 166 | 167 | // Overworld shape config 168 | val shape = GenerationShapeConfig(-64, 384, 1, 2) 169 | val testSampler = 170 | ChunkNoiseSampler( 171 | 16 / shape.horizontalCellBlockCount(), config, chunkPos.startX, chunkPos.startZ, 172 | shape, object : DensityFunctionTypes.Beardifying { 173 | override fun maxValue(): Double = 0.0 174 | override fun minValue(): Double = 0.0 175 | override fun sample(pos: NoisePos): Double = 0.0 176 | override fun fill(densities: DoubleArray, applier: EachApplier) { 177 | densities.fill(0.0) 178 | } 179 | }, settings, null, Blender.getNoBlending() 180 | ) 181 | 182 | var method: KFunction<*>? = null 183 | for (m: KFunction<*> in testSampler::class.declaredFunctions) { 184 | if (m.name == "createMultiNoiseSampler") { 185 | method = m 186 | break 187 | } 188 | } 189 | val sampler = method!!.call(testSampler, config.noiseRouter, listOf()) as MultiNoiseSampler 190 | for (x in 0..15) { 191 | for (y in -64..319) { 192 | for (z in 0..15) { 193 | val result = sampler.sample(x, y, z) 194 | 195 | val valueArr = JsonArray() 196 | valueArr.add(x) 197 | valueArr.add(y) 198 | valueArr.add(z) 199 | 200 | valueArr.add(result.temperatureNoise) 201 | valueArr.add(result.humidityNoise) 202 | valueArr.add(result.continentalnessNoise) 203 | valueArr.add(result.erosionNoise) 204 | valueArr.add(result.depth) 205 | valueArr.add(result.weirdnessNoise) 206 | 207 | rootJson.add(valueArr) 208 | } 209 | } 210 | } 211 | 212 | return rootJson 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/NoiseParameters.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.util.math.noise.DoublePerlinNoiseSampler 11 | 12 | class NoiseParameters : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "noise_parameters.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val noisesJson = JsonObject() 19 | val noiseParameterRegistry = 20 | server.registryManager.getOrThrow(RegistryKeys.NOISE_PARAMETERS) 21 | for (noise in noiseParameterRegistry) { 22 | noisesJson.add( 23 | noiseParameterRegistry.getId(noise)!!.path, 24 | DoublePerlinNoiseSampler.NoiseParameters.CODEC.encodeStart( 25 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 26 | noise 27 | ).getOrThrow() 28 | ) 29 | } 30 | 31 | return noisesJson 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Packets.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.SharedConstants 8 | import net.minecraft.network.NetworkPhase 9 | import net.minecraft.network.packet.PacketType 10 | import net.minecraft.network.state.* 11 | import net.minecraft.server.MinecraftServer 12 | 13 | 14 | class Packets : Extractor.Extractor { 15 | override fun fileName(): String { 16 | return "packets.json" 17 | } 18 | 19 | override fun extract(server: MinecraftServer): JsonElement { 20 | val packetsJson = JsonObject() 21 | 22 | val clientBound = arrayOf( 23 | QueryStates.S2C_FACTORY.buildUnbound(), 24 | LoginStates.S2C_FACTORY.buildUnbound(), 25 | ConfigurationStates.S2C_FACTORY.buildUnbound(), 26 | PlayStateFactories.S2C.buildUnbound() 27 | ) 28 | 29 | val serverBound = arrayOf( 30 | HandshakeStates.C2S_FACTORY.buildUnbound(), 31 | QueryStates.C2S_FACTORY.buildUnbound(), 32 | LoginStates.C2S_FACTORY.buildUnbound(), 33 | ConfigurationStates.C2S_FACTORY.buildUnbound(), 34 | PlayStateFactories.C2S.buildUnbound() 35 | ) 36 | val serverBoundJson = serializeServerBound(serverBound) 37 | val clientBoundJson = serializeClientBound(clientBound) 38 | packetsJson.addProperty("version", SharedConstants.getProtocolVersion()) 39 | packetsJson.add("serverbound", serverBoundJson) 40 | packetsJson.add("clientbound", clientBoundJson) 41 | return packetsJson 42 | } 43 | 44 | 45 | private fun serializeServerBound( 46 | packets: Array 47 | ): JsonObject { 48 | val handshakeArray = JsonArray() 49 | val statusArray = JsonArray() 50 | val loginArray = JsonArray() 51 | val configArray = JsonArray() 52 | val playArray = JsonArray() 53 | 54 | for (factory in packets) { 55 | factory.forEachPacketType { type: PacketType<*>, _: Int -> 56 | when (factory.phase()!!) { 57 | NetworkPhase.HANDSHAKING -> handshakeArray.add(type.id().path) 58 | NetworkPhase.PLAY -> playArray.add(type.id().path) 59 | NetworkPhase.STATUS -> statusArray.add(type.id().path) 60 | NetworkPhase.LOGIN -> loginArray.add(type.id().path) 61 | NetworkPhase.CONFIGURATION -> configArray.add(type.id().path) 62 | } 63 | } 64 | } 65 | 66 | val finalJson = JsonObject() 67 | finalJson.add("handshake", handshakeArray) 68 | finalJson.add("status", statusArray) 69 | finalJson.add("login", loginArray) 70 | finalJson.add("config", configArray) 71 | finalJson.add("play", playArray) 72 | return finalJson 73 | } 74 | 75 | private fun serializeClientBound( 76 | packets: Array 77 | ): JsonObject { 78 | val statusArray = JsonArray() 79 | val loginArray = JsonArray() 80 | val configArray = JsonArray() 81 | val playArray = JsonArray() 82 | 83 | for (factory in packets) { 84 | factory.forEachPacketType { type: PacketType<*>, _: Int -> 85 | when (factory.phase()!!) { 86 | NetworkPhase.HANDSHAKING -> error("Client bound Packet should have no handshake") 87 | NetworkPhase.PLAY -> playArray.add(type.id().path) 88 | NetworkPhase.STATUS -> statusArray.add(type.id().path) 89 | NetworkPhase.LOGIN -> loginArray.add(type.id().path) 90 | NetworkPhase.CONFIGURATION -> configArray.add(type.id().path) 91 | } 92 | } 93 | } 94 | val finalJson = JsonObject() 95 | finalJson.add("status", statusArray) 96 | finalJson.add("login", loginArray) 97 | finalJson.add("config", configArray) 98 | finalJson.add("play", playArray) 99 | return finalJson 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Particles.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | 10 | class Particles : Extractor.Extractor { 11 | override fun fileName(): String { 12 | return "particles.json" 13 | } 14 | 15 | override fun extract(server: MinecraftServer): JsonElement { 16 | val particlesJson = JsonArray() 17 | for (particle in Registries.PARTICLE_TYPE) { 18 | particlesJson.add( 19 | Registries.PARTICLE_TYPE.getId(particle)!!.path, 20 | ) 21 | } 22 | 23 | return particlesJson 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/PlacedFeatures.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.world.gen.feature.PlacedFeature 11 | 12 | class PlacedFeatures : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "placed_feature.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val finalJson = JsonObject() 19 | val registry = 20 | server.registryManager.getOrThrow(RegistryKeys.PLACED_FEATURE) 21 | for (setting in registry) { 22 | finalJson.add( 23 | registry.getId(setting)!!.path, 24 | PlacedFeature.CODEC.encodeStart( 25 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 26 | setting 27 | ).getOrThrow() 28 | ) 29 | } 30 | 31 | return finalJson 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Recipes.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.recipe.Recipe 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | 11 | class Recipes : Extractor.Extractor { 12 | override fun fileName(): String { 13 | return "recipes.json" 14 | } 15 | 16 | override fun extract(server: MinecraftServer): JsonElement { 17 | val recipesJson = JsonArray() 18 | 19 | for (recipeRaw in server.recipeManager.values()) { 20 | val recipe = recipeRaw.value 21 | recipesJson.add( 22 | Recipe.CODEC.encodeStart( 23 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 24 | recipe 25 | ).getOrThrow() 26 | ) 27 | } 28 | return recipesJson 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Screens.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class Screens : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "screens.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val screensJson = JsonArray() 16 | for (screen in Registries.SCREEN_HANDLER) { 17 | screensJson.add( 18 | Registries.SCREEN_HANDLER.getId(screen)!!.path, 19 | ) 20 | } 21 | 22 | return screensJson 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Sounds.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | 10 | class Sounds : Extractor.Extractor { 11 | override fun fileName(): String { 12 | return "sounds.json" 13 | } 14 | 15 | override fun extract(server: MinecraftServer): JsonElement { 16 | val soundJson = JsonArray() 17 | for (sound in Registries.SOUND_EVENT) { 18 | soundJson.add( 19 | Registries.SOUND_EVENT.getId(sound)!!.path, 20 | ) 21 | } 22 | 23 | return soundJson 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/StatusEffects.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class StatusEffects : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "status_effects.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val statusJson = JsonArray() 16 | for (status in Registries.STATUS_EFFECT) { 17 | println(status.translationKey) 18 | statusJson.add( 19 | Registries.STATUS_EFFECT.getId(status)!!.path, 20 | ) 21 | } 22 | 23 | return statusJson 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/SyncedRegistries.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.Codec 6 | import com.mojang.serialization.JsonOps 7 | import de.snowii.extractor.Extractor 8 | import net.minecraft.registry.* 9 | import net.minecraft.server.MinecraftServer 10 | import java.util.stream.Stream 11 | 12 | 13 | class SyncedRegistries : Extractor.Extractor { 14 | override fun fileName(): String { 15 | return "synced_registries.json" 16 | } 17 | 18 | override fun extract(server: MinecraftServer): JsonElement { 19 | val registries: Stream> = RegistryLoader.SYNCED_REGISTRIES.stream() 20 | val json = JsonObject() 21 | registries.forEach { entry -> 22 | json.add( 23 | entry.key().value.path, 24 | mapJson(entry, server.registryManager, server.combinedDynamicRegistries) 25 | ) 26 | } 27 | return json 28 | } 29 | 30 | private fun mapJson( 31 | registryEntry: RegistryLoader.Entry, 32 | registryManager: DynamicRegistryManager.Immutable, 33 | combinedRegistries: CombinedDynamicRegistries 34 | ): JsonObject { 35 | val codec: Codec = registryEntry.elementCodec() 36 | val registry: Registry = registryManager.getOrThrow(registryEntry.key()) 37 | val json = JsonObject() 38 | registry.streamEntries().forEach { entry -> 39 | json.add( 40 | entry.key.orElseThrow().value.path, 41 | codec.encodeStart( 42 | combinedRegistries.combinedRegistryManager.getOps(JsonOps.INSTANCE), 43 | entry.value() 44 | ).getOrThrow() 45 | ) 46 | } 47 | return json 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/Tags.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.tag.TagPacketSerializer 8 | import net.minecraft.server.MinecraftServer 9 | 10 | 11 | class Tags : Extractor.Extractor { 12 | override fun fileName(): String { 13 | return "tags.json" 14 | } 15 | 16 | override fun extract(server: MinecraftServer): JsonElement { 17 | val tagsJson = JsonObject() 18 | 19 | val tags = TagPacketSerializer.serializeTags(server.combinedDynamicRegistries) 20 | 21 | for (tag in tags.entries) { 22 | val tagGroupTagsJson = JsonObject() 23 | val tagValues = 24 | tag.value.toRegistryTags(server.combinedDynamicRegistries.combinedRegistryManager.getOrThrow(tag.key)) 25 | for (value in tagValues.tags) { 26 | val tagGroupTagsJsonArray = JsonArray() 27 | for (tagVal in value.value) { 28 | tagGroupTagsJsonArray.add(tagVal.key.orElseThrow().value.path) 29 | } 30 | tagGroupTagsJson.add(value.key.id.toString(), tagGroupTagsJsonArray) 31 | } 32 | tagsJson.add(tag.key.value.path, tagGroupTagsJson) 33 | } 34 | 35 | return tagsJson 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/WorldGenFeatures.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import com.mojang.serialization.JsonOps 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.registry.RegistryKeys 8 | import net.minecraft.registry.RegistryOps 9 | import net.minecraft.server.MinecraftServer 10 | import net.minecraft.world.gen.feature.ConfiguredFeature 11 | 12 | class WorldGenFeatures : Extractor.Extractor { 13 | override fun fileName(): String { 14 | return "gen_features.json" 15 | } 16 | 17 | override fun extract(server: MinecraftServer): JsonElement { 18 | val finalJson = JsonObject() 19 | val registry = 20 | server.registryManager.getOrThrow(RegistryKeys.CONFIGURED_FEATURE) 21 | for (setting in registry) { 22 | finalJson.add( 23 | registry.getId(setting)!!.path, 24 | ConfiguredFeature.CODEC.encodeStart( 25 | RegistryOps.of(JsonOps.INSTANCE, server.registryManager), 26 | setting 27 | ).getOrThrow() 28 | ) 29 | } 30 | 31 | return finalJson 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/EntityPose.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.entity.EntityPose 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class EntityPose : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "entity_pose.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val poseesJson = JsonArray() 16 | for (pose in EntityPose.entries) { 17 | poseesJson.add( 18 | pose.name, 19 | ) 20 | } 21 | 22 | return poseesJson 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/EntityStatuses.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.entity.EntityStatuses 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class EntityStatuses : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "entity_statuses.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val jsonObject = JsonObject() 16 | val fields = EntityStatuses::class.java.declaredFields 17 | 18 | for (field in fields) { 19 | if (field.type == Byte::class.javaPrimitiveType || field.type == Byte::class.java) { 20 | if (field.name.startsWith("field")) continue 21 | field.isAccessible = true 22 | val byteValue = field.get(null) as Byte 23 | jsonObject.addProperty(field.name, byteValue) 24 | } 25 | } 26 | 27 | return jsonObject 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/Properties.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonObject 6 | import de.snowii.extractor.Extractor 7 | import net.minecraft.server.MinecraftServer 8 | import net.minecraft.state.property.BooleanProperty 9 | import net.minecraft.state.property.EnumProperty 10 | import net.minecraft.state.property.IntProperty 11 | import net.minecraft.state.property.Property 12 | import java.lang.reflect.Modifier 13 | 14 | class Properties : Extractor.Extractor { 15 | override fun fileName(): String { 16 | return "properties.json" 17 | } 18 | 19 | override fun extract(server: MinecraftServer): JsonElement { 20 | val topLevelJson = JsonArray() 21 | 22 | for (field in net.minecraft.state.property.Properties::class.java.declaredFields) { 23 | if (Modifier.isStatic(field.modifiers)) { 24 | val maybeProperty = field.get(null) 25 | if (maybeProperty is Property<*>) { 26 | val property = JsonObject() 27 | // The key used by Blocks.json to map to a property 28 | property.addProperty("hash_key", maybeProperty.hashCode()) 29 | // The unique enum name 30 | property.addProperty("enum_name", field.name.lowercase()) 31 | // What the enum is serialized as, may overlap with others 32 | property.addProperty("serialized_name", maybeProperty.name.lowercase()) 33 | 34 | when (maybeProperty) { 35 | is BooleanProperty -> { 36 | property.addProperty("type", "boolean") 37 | } 38 | 39 | is IntProperty -> { 40 | var min: Int? = null 41 | var max: Int? = null 42 | for (intField in IntProperty::class.java.declaredFields) { 43 | intField.trySetAccessible() 44 | if (intField.name == "min") { 45 | min = intField.get(maybeProperty) as Int 46 | } else if (intField.name == "max") { 47 | max = intField.get(maybeProperty) as Int 48 | } 49 | } 50 | property.addProperty("type", "int") 51 | property.addProperty("min", min!!) 52 | property.addProperty("max", max!!) 53 | } 54 | 55 | is EnumProperty<*> -> { 56 | property.addProperty("type", "enum") 57 | val enumArr = JsonArray() 58 | for (value in maybeProperty.values) { 59 | enumArr.add(value.toString().lowercase()) 60 | } 61 | property.add("values", enumArr) 62 | } 63 | 64 | else -> throw Exception("Unhandled property type: " + maybeProperty.javaClass.toString()) 65 | } 66 | 67 | topLevelJson.add(property) 68 | } 69 | } 70 | } 71 | return topLevelJson 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/ScoreboardDisplaySlot.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.scoreboard.ScoreboardDisplaySlot 7 | import net.minecraft.server.MinecraftServer 8 | 9 | class ScoreboardDisplaySlot : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "scoreboard_display_slot.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val finalJson = JsonArray() 16 | for (slot in ScoreboardDisplaySlot.entries) { 17 | finalJson.add( 18 | slot.name, 19 | ) 20 | } 21 | 22 | return finalJson 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/SoundCategory.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonArray 4 | import com.google.gson.JsonElement 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.sound.SoundCategory 8 | 9 | class SoundCategory : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "sound_category.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val categoriesJson = JsonArray() 16 | for (category in SoundCategory.entries) { 17 | categoriesJson.add( 18 | category.name, 19 | ) 20 | } 21 | 22 | return categoriesJson 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/SpawnEgg.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.item.SpawnEggItem 7 | import net.minecraft.registry.Registries 8 | import net.minecraft.server.MinecraftServer 9 | 10 | class SpawnEgg : Extractor.Extractor { 11 | override fun fileName(): String { 12 | return "spawn_egg.json" 13 | } 14 | 15 | override fun extract(server: MinecraftServer): JsonElement { 16 | val eggJson = JsonObject() 17 | 18 | for (spawnEggItem in SpawnEggItem.getAll()) { 19 | val type = spawnEggItem.getEntityType(server.registryManager, spawnEggItem.defaultStack) 20 | eggJson.addProperty( 21 | Registries.ITEM.getRawId(spawnEggItem).toString(), 22 | Registries.ENTITY_TYPE.getId(type).path 23 | ) 24 | } 25 | return eggJson 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/Translations.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import com.google.gson.JsonElement 6 | import com.google.gson.JsonObject 7 | import de.snowii.extractor.Extractor 8 | import net.minecraft.server.MinecraftServer 9 | import java.io.InputStreamReader 10 | import java.nio.charset.StandardCharsets 11 | 12 | class Translations : Extractor.Extractor { 13 | private val gson: Gson = GsonBuilder().disableHtmlEscaping().create() 14 | 15 | override fun fileName(): String { 16 | return "en_us.json" 17 | } 18 | 19 | override fun extract(server: MinecraftServer): JsonElement { 20 | val inputStream = this.javaClass.getResourceAsStream("/assets/minecraft/lang/en_us.json") 21 | ?: throw IllegalArgumentException("Could not find lang en_us.json") 22 | 23 | return inputStream.use { stream -> 24 | gson.fromJson( 25 | InputStreamReader(stream, StandardCharsets.UTF_8), 26 | JsonObject::class.java 27 | ) as JsonObject 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/snowii/extractor/extractors/non_registry/WorldEvent.kt: -------------------------------------------------------------------------------- 1 | package de.snowii.extractor.extractors.non_registry 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonObject 5 | import de.snowii.extractor.Extractor 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.world.WorldEvents 8 | 9 | class WorldEvent : Extractor.Extractor { 10 | override fun fileName(): String { 11 | return "world_event.json" 12 | } 13 | 14 | override fun extract(server: MinecraftServer): JsonElement { 15 | val jsonObject = JsonObject() 16 | val fields = WorldEvents::class.java.declaredFields 17 | 18 | for (field in fields) { 19 | if (field.type == Int::class.javaPrimitiveType || field.type == Int::class.java) { 20 | if (field.name.startsWith("field")) continue 21 | field.isAccessible = true 22 | val intValue = field.get(null) as Int 23 | jsonObject.addProperty(field.name, intValue) 24 | } 25 | } 26 | 27 | return jsonObject 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "extractor", 4 | "version": "${version}", 5 | "name": "pumpkin-extractor", 6 | "description": "", 7 | "authors": [], 8 | "contact": {}, 9 | "license": "MIT", 10 | "environment": "*", 11 | "entrypoints": { 12 | "main": [ 13 | "de.snowii.extractor.Extractor" 14 | ] 15 | }, 16 | "depends": { 17 | "fabricloader": ">=${loader_version}", 18 | "fabric-language-kotlin": ">=${kotlin_loader_version}", 19 | "fabric": "*", 20 | "minecraft": "${minecraft_version}" 21 | } 22 | } 23 | --------------------------------------------------------------------------------