├── .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 | [](https://opensource.org/licenses/MIT)
4 | 
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 |
--------------------------------------------------------------------------------