├── .gitignore ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── kaptainwutax │ └── seedcracker │ ├── Features.java │ ├── SeedCracker.java │ ├── command │ ├── ClientCommand.java │ ├── CrackerCommand.java │ ├── DataCommand.java │ ├── FinderCommand.java │ ├── RenderCommand.java │ └── VersionCommand.java │ ├── cracker │ ├── BiomeData.java │ ├── DataAddedEvent.java │ ├── HashedSeedData.java │ ├── PillarData.java │ ├── decorator │ │ ├── Decorator.java │ │ ├── Dungeon.java │ │ └── EmeraldOre.java │ └── storage │ │ ├── DataStorage.java │ │ ├── ProgressListener.java │ │ ├── ScheduledSet.java │ │ └── TimeMachine.java │ ├── finder │ ├── BiomeFinder.java │ ├── BlockFinder.java │ ├── Finder.java │ ├── FinderBuilder.java │ ├── FinderQueue.java │ ├── decorator │ │ ├── DesertWellFinder.java │ │ ├── DungeonFinder.java │ │ ├── EndGatewayFinder.java │ │ ├── EndPillarsFinder.java │ │ ├── OreFinder.java │ │ └── ore │ │ │ └── EmeraldOreFinder.java │ └── structure │ │ ├── AbstractTempleFinder.java │ │ ├── BuriedTreasureFinder.java │ │ ├── DesertPyramidFinder.java │ │ ├── EndCityFinder.java │ │ ├── IglooFinder.java │ │ ├── JunglePyramidFinder.java │ │ ├── MansionFinder.java │ │ ├── MonumentFinder.java │ │ ├── PieceFinder.java │ │ ├── ShipwreckFinder.java │ │ └── SwampHutFinder.java │ ├── init │ └── ClientCommands.java │ ├── mixin │ ├── ClientPlayNetworkHandlerMixin.java │ ├── ClientPlayerEntityMixin.java │ ├── ClientWorldMixin.java │ ├── DimensionTypeMixin.java │ ├── DummyProfilerMixin.java │ ├── GameRendererMixin.java │ └── ServerChunkManagerMixin.java │ ├── profile │ ├── CustomProfile.java │ ├── FinderConfig.java │ ├── FinderProfile.java │ ├── NopeProfile.java │ ├── VanillaProfile.java │ └── YoloProfile.java │ ├── render │ ├── Color.java │ ├── Cube.java │ ├── Cuboid.java │ ├── Line.java │ ├── RenderQueue.java │ └── Renderer.java │ └── util │ ├── BiomeFixer.java │ ├── Log.java │ ├── PosIterator.java │ └── Predicates.java └── resources ├── assets └── seedcracker │ ├── icon.png │ └── lang │ ├── en_us.json │ └── zh_cn.json ├── fabric.mod.json └── seedcracker.mixins.json /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # idea 9 | 10 | .idea/ 11 | *.iml 12 | *.ipr 13 | *.iws 14 | 15 | # vscode 16 | 17 | .settings/ 18 | .vscode/ 19 | bin/ 20 | .classpath 21 | .project 22 | 23 | # fabric 24 | 25 | run/ 26 | logs/ 27 | 28 | src/main/java/kaptainwutax/stronghold/ 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 KaptainWutax 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 | # SeedCracker [![Github All Releases](https://img.shields.io/github/downloads/KaptainWutax/SeedCracker/total.svg)]() 2 | 3 | ## Installation 4 | 5 | ### Vanilla Launcher 6 | 7 | Download and install the [fabric mod loader](https://fabricmc.net/use/). 8 | 9 | ### MultiMC 10 | 11 | Add a new minecraft instance and press "Install Fabric" in the instance options. 12 | 13 | 14 | Then download the lastest [release](https://github.com/KaptainWutax/SeedCracker/releases) of SeedCracker and put the `.jar` file in your mods directory, either `%appdata%/.minecraft/mods/` folder for the vanilla launcher or your own MultiMC instance folder. 15 | 16 | ## Usage 17 | 18 | Run minecraft with the mod installed and run around in the world. Once the mod has collected enough data, it will start the cracking process automatically and output the seed in chat. For the process to start, the amount of data that needs to be collected varies depending on the type of feature. `/seed data bits` can be used to see how much progress has been done. 19 | 20 | ### Supported Structures 21 | - Ocean Monument 22 | - End City 23 | - Buried Treasure 24 | - Desert Pyramid 25 | - Jungle Temple 26 | - Swamp Hut 27 | - Shipwreck 28 | 29 | ### Supported Decorators 30 | - Dungeon 31 | - End Gateway 32 | - Desert Well 33 | - Emerald Ore 34 | 35 | ## Commands 36 | 37 | The command prefix for this mod is /seed. 38 | 39 | ### Render Command 40 | -`/seed render outlines ` 41 | 42 | This command only affects the renderer feedback. The default value is 'XRAY' and highlights data through blocks. You can set the render mod to 'ON' for more standard rendering. 43 | 44 | ### Finder Command 45 | -`/seed finder type (ON/OFF)` 46 | 47 | -`/seed finder category (BIOMES/ORES/OTHERS/STRUCTURES) (ON/OFF)` 48 | 49 | This command is used to disable finders in case you are aware the data is wrong. For example, a map generated in 1.14 has different decorators and would require you to disable them while going through those chunks. 50 | 51 | ### Data Command 52 | - `/seed data clear` 53 | 54 | Clears all the collected data without requiring a relog. This is useful for multi-world servers. 55 | 56 | - `/seed data bits` 57 | 58 | Display how many bits of information have been collected. Even though this is an approximate, it serves as a good basis to guess when the brute-forcing should start. 59 | 60 | ### Cracker Command 61 | - `/seed cracker ` 62 | 63 | Enables or disables the mod completely. Unlike the other commands, this one is persistent across reloads. 64 | 65 | ## Video Tutorial 66 | 67 | https://youtu.be/1ChmLi9og8Q 68 | 69 | ## Upcoming Features 70 | 71 | A list of features I have on my mind... they won't necessarily be implemented in this order if at all. 72 | 73 | - SHA2 brute-forcing, auxiliary to biomes search. /implemented 74 | - Dungeon floor cracker, fast lattice reversal. /implemented 75 | - Stronghold portal room cracker. (alternative to dungeon floor?) 76 | - Faster brute-forcing by reorganizing located features list. /implemented 77 | - End and nether biome finders. (nether would mostly be in preparation for 1.16) /implemented 78 | 79 | ## Setting up the Workspace 80 | 81 | -Clone the repository. 82 | 83 | -Run `gradlew genSources `. 84 | 85 | ## Building the Mod 86 | 87 | -Update the version in `build.gradle` and `fabric.mod.json`. 88 | 89 | -Run `gradlew build`. 90 | 91 | ## Contributors 92 | 93 | [KaptainWutax](https://github.com/KaptainWutax) - Author 94 | 95 | [neil](https://www.youtube.com/watch?v=aUuPSZVPH8E) - Video Tutorial 96 | 97 | [Nekzuris](https://github.com/Nekzuris) - README 98 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.8-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | sourceCompatibility = JavaVersion.VERSION_16 7 | targetCompatibility = JavaVersion.VERSION_16 8 | 9 | archivesBaseName = project.archives_base_name 10 | version = project.mod_version 11 | group = project.maven_group 12 | 13 | repositories { 14 | maven { 15 | url "https://jitpack.io" 16 | } 17 | } 18 | 19 | dependencies { 20 | //to change the versions see the gradle.properties file 21 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 22 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 23 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 24 | 25 | modApi('com.github.KaptainWutax:MathUtils:6c2d50eacad0241ff76119e6e703b70bac4b4bce') {transitive = false} 26 | modApi('com.github.KaptainWutax:SeedUtils:8e310c079346fa55077fd1786b50dae0d2025336') {transitive = false} 27 | modApi('com.github.KaptainWutax:FeatureUtils:25f73f26289a65a314cd66badc3c433d7f8c37b0') {transitive = false} 28 | modApi('com.github.KaptainWutax:BiomeUtils:590f697a2ccb6c6bdba8e2fea891a25ace75c947') {transitive = false} 29 | modApi('com.github.KaptainWutax:ChunkRandomReversal:209eefb8ed2bd097e3c55d3934ba508b664443da') {transitive = false} 30 | modApi('com.github.KaptainWutax:LattiCG:38f0b3d33e15ad2e6ce9ddb1f588e2b9a8c96174') {transitive = false} 31 | 32 | // Fabric API. This is technically optional, but you probably want it anyway. 33 | // modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 34 | 35 | // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. 36 | // You may need to force-disable transitiveness on them. 37 | } 38 | 39 | minecraft { 40 | refmapName = "seedcracker.refmap.json" 41 | } 42 | 43 | processResources { 44 | inputs.property "version", project.version 45 | 46 | filesMatching("fabric.mod.json") { 47 | expand "version": project.version 48 | } 49 | } 50 | 51 | tasks.withType(JavaCompile).configureEach { 52 | it.options.encoding = "UTF-8" 53 | it.options.release = 16 54 | } 55 | 56 | java { 57 | withSourcesJar() 58 | } 59 | 60 | jar { 61 | from("LICENSE") { 62 | rename { "${it}_${project.archivesBaseName}"} 63 | } 64 | } 65 | 66 | // configure the maven publication 67 | publishing { 68 | publications { 69 | mavenJava(MavenPublication) { 70 | // add all the jars that should be included when publishing to maven 71 | artifact(remapJar) { 72 | builtBy remapJar 73 | } 74 | artifact(sourcesJar) { 75 | builtBy remapSourcesJar 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | # Fabric Properties 4 | # check these on https://fabricmc.net/use 5 | minecraft_version=1.17 6 | yarn_mappings=1.17+build.1 7 | loader_version=0.11.3 8 | # Mod Properties 9 | mod_version=0.2.3-beta 10 | maven_group=kaptainwutax 11 | archives_base_name=seedcracker 12 | # Dependencies 13 | # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api 14 | fabric_version=0.34.9+1.17 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaptainWutax/SeedCracker/9188a0f9003d3101d23bdafba15c8f4834d7fe5a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 02 11:00:35 EDT 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or 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 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /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 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | jcenter() 4 | maven { 5 | name = 'Fabric' 6 | url = 'https://maven.fabricmc.net/' 7 | } 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/Features.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker; 2 | 3 | import kaptainwutax.featureutils.decorator.DesertWell; 4 | import kaptainwutax.featureutils.decorator.EndGateway; 5 | import kaptainwutax.featureutils.structure.*; 6 | import kaptainwutax.seedcracker.cracker.decorator.Dungeon; 7 | import kaptainwutax.seedcracker.cracker.decorator.EmeraldOre; 8 | import kaptainwutax.seedutils.mc.MCVersion; 9 | 10 | public class Features { 11 | 12 | public static BastionRemnant BASTION_REMNANT; 13 | public static BuriedTreasure BURIED_TREASURE; 14 | public static DesertPyramid DESERT_PYRAMID; 15 | public static EndCity END_CITY; 16 | public static Fortress FORTRESS; 17 | public static Igloo IGLOO; 18 | public static JunglePyramid JUNGLE_PYRAMID; 19 | public static Mansion MANSION; 20 | public static Mineshaft MINESHAFT; 21 | public static Monument MONUMENT; 22 | public static NetherFossil NETHER_FOSSIL; 23 | public static OceanRuin OCEAN_RUIN; 24 | public static PillagerOutpost PILLAGER_OUTPOST; 25 | public static RuinedPortal RUINED_PORTAL; 26 | public static Shipwreck SHIPWRECK; 27 | public static Stronghold STRONGHOLD; 28 | public static SwampHut SWAMP_HUT; 29 | public static Village VILLAGE; 30 | 31 | public static EndGateway END_GATEWAY; 32 | public static DesertWell DESERT_WELL; 33 | public static EmeraldOre EMERALD_ORE; 34 | public static Dungeon DUNGEON; 35 | 36 | public static void init(MCVersion version) { 37 | safe(() -> BASTION_REMNANT = new BastionRemnant(version)); 38 | safe(() -> BURIED_TREASURE = new BuriedTreasure(version)); 39 | safe(() -> DESERT_PYRAMID = new DesertPyramid(version)); 40 | safe(() -> END_CITY = new EndCity(version)); 41 | safe(() -> FORTRESS = new Fortress(version)); 42 | safe(() -> IGLOO = new Igloo(version)); 43 | safe(() -> JUNGLE_PYRAMID = new JunglePyramid(version)); 44 | safe(() -> MANSION = new Mansion(version)); 45 | safe(() -> MINESHAFT = new Mineshaft(version)); 46 | safe(() -> MONUMENT = new Monument(version)); 47 | safe(() -> NETHER_FOSSIL = new NetherFossil(version)); 48 | safe(() -> OCEAN_RUIN = new OceanRuin(version)); 49 | safe(() -> PILLAGER_OUTPOST = new PillagerOutpost(version)); 50 | safe(() -> RUINED_PORTAL = new RuinedPortal(version)); 51 | safe(() -> SHIPWRECK = new Shipwreck(version)); 52 | safe(() -> STRONGHOLD = new Stronghold(version)); 53 | safe(() -> SWAMP_HUT = new SwampHut(version)); 54 | safe(() -> VILLAGE = new Village(version)); 55 | 56 | safe(() -> END_GATEWAY = new EndGateway(version)); 57 | safe(() -> DESERT_WELL = new DesertWell(version)); 58 | safe(() -> EMERALD_ORE = new EmeraldOre(version)); 59 | safe(() -> DUNGEON = new Dungeon(version)); 60 | } 61 | 62 | private static void safe(Runnable runnable) { 63 | try {runnable.run();} catch(Exception e) {} 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/SeedCracker.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker; 2 | 3 | import kaptainwutax.seedcracker.command.ClientCommand; 4 | import kaptainwutax.seedcracker.cracker.storage.DataStorage; 5 | import kaptainwutax.seedcracker.finder.FinderQueue; 6 | import kaptainwutax.seedcracker.render.RenderQueue; 7 | import kaptainwutax.seedutils.mc.MCVersion; 8 | import net.fabricmc.api.ModInitializer; 9 | import net.minecraft.util.Formatting; 10 | 11 | public class SeedCracker implements ModInitializer { 12 | 13 | public static MCVersion MC_VERSION = MCVersion.v1_16_2; 14 | 15 | private static final SeedCracker INSTANCE = new SeedCracker(); 16 | private final DataStorage dataStorage = new DataStorage(); 17 | private boolean active = true; 18 | 19 | @Override 20 | public void onInitialize() { 21 | Features.init(MC_VERSION); 22 | RenderQueue.get().add("hand", FinderQueue.get()::renderFinders); 23 | } 24 | 25 | public static SeedCracker get() { 26 | return INSTANCE; 27 | } 28 | 29 | public DataStorage getDataStorage() { 30 | return this.dataStorage; 31 | } 32 | 33 | public boolean isActive() { 34 | return this.active; 35 | } 36 | 37 | public void setActive(boolean active) { 38 | this.active = active; 39 | 40 | if(this.active) { 41 | ClientCommand.sendFeedback("SeedCracker is active.", Formatting.GREEN, true); 42 | } else { 43 | ClientCommand.sendFeedback("SeedCracker is not active.", Formatting.RED, true); 44 | } 45 | } 46 | 47 | public void reset() { 48 | SeedCracker.get().getDataStorage().clear(); 49 | FinderQueue.get().clear(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/ClientCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 5 | import kaptainwutax.seedcracker.init.ClientCommands; 6 | import net.minecraft.client.MinecraftClient; 7 | import net.minecraft.server.command.ServerCommandSource; 8 | import net.minecraft.text.LiteralText; 9 | import net.minecraft.util.Formatting; 10 | 11 | import static net.minecraft.server.command.CommandManager.literal; 12 | 13 | public abstract class ClientCommand { 14 | 15 | public abstract String getName(); 16 | 17 | public abstract void build(LiteralArgumentBuilder builder); 18 | 19 | public static void sendFeedback(String message, Formatting color, boolean overlay) { 20 | MinecraftClient.getInstance().player.sendMessage(new LiteralText(message).formatted(color), overlay); 21 | } 22 | 23 | public final void register(CommandDispatcher dispatcher) { 24 | LiteralArgumentBuilder builder = literal(this.getName()); 25 | this.build(builder); 26 | dispatcher.register(literal(ClientCommands.PREFIX).then(builder)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/CrackerCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import net.minecraft.server.command.ServerCommandSource; 6 | 7 | import static net.minecraft.server.command.CommandManager.literal; 8 | 9 | public class CrackerCommand extends ClientCommand { 10 | 11 | @Override 12 | public String getName() { 13 | return "cracker"; 14 | } 15 | 16 | @Override 17 | public void build(LiteralArgumentBuilder builder) { 18 | builder.then(literal("ON").executes(context -> this.setActive(true))) 19 | .then(literal("OFF").executes(context -> this.setActive(false))); 20 | } 21 | 22 | private int setActive(boolean flag) { 23 | SeedCracker.get().setActive(flag); 24 | return 0; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/DataCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.storage.DataStorage; 7 | import net.minecraft.server.command.ServerCommandSource; 8 | import net.minecraft.util.Formatting; 9 | 10 | import static net.minecraft.server.command.CommandManager.literal; 11 | 12 | public class DataCommand extends ClientCommand { 13 | 14 | @Override 15 | public String getName() { 16 | return "data"; 17 | } 18 | 19 | @Override 20 | public void build(LiteralArgumentBuilder builder) { 21 | builder.then(literal("clear") 22 | .executes(this::clear) 23 | ); 24 | 25 | builder.then(literal("bits") 26 | .executes(this::printBits) 27 | ); 28 | } 29 | 30 | public int clear(CommandContext context) { 31 | SeedCracker.get().reset(); 32 | sendFeedback("Cleared data storage and finders.", Formatting.GREEN, false); 33 | return 0; 34 | } 35 | 36 | private int printBits(CommandContext context) { 37 | DataStorage s = SeedCracker.get().getDataStorage(); 38 | String message = "You currently have collected " + (int)s.getBaseBits() + " bits out of " + (int)s.getWantedBits() + "."; 39 | sendFeedback(message, Formatting.GREEN, false); 40 | return 0; 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/FinderCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcracker.finder.Finder; 5 | import kaptainwutax.seedcracker.finder.FinderQueue; 6 | import net.minecraft.server.command.ServerCommandSource; 7 | import net.minecraft.util.Formatting; 8 | 9 | import static net.minecraft.server.command.CommandManager.literal; 10 | 11 | public class FinderCommand extends ClientCommand { 12 | 13 | @Override 14 | public String getName() { 15 | return "finder"; 16 | } 17 | 18 | @Override 19 | public void build(LiteralArgumentBuilder builder) { 20 | for(Finder.Type finderType: Finder.Type.values()) { 21 | builder.then(literal("type") 22 | .then(literal(finderType.toString()) 23 | .then(literal("ON").executes(context -> this.setFinderType(finderType, true))) 24 | .then(literal("OFF").executes(context -> this.setFinderType(finderType, false)))) 25 | .executes(context -> this.printFinderType(finderType)) 26 | ); 27 | } 28 | 29 | for(Finder.Category finderCategory: Finder.Category.values()) { 30 | builder.then(literal("category") 31 | .then(literal(finderCategory.toString()) 32 | .then(literal("ON").executes(context -> this.setFinderCategory(finderCategory, true))) 33 | .then(literal("OFF").executes(context -> this.setFinderCategory(finderCategory, false)))) 34 | .executes(context -> this.printFinderCategory(finderCategory)) 35 | ); 36 | } 37 | } 38 | 39 | private int printFinderCategory(Finder.Category finderCategory) { 40 | Finder.Type.getForCategory(finderCategory).forEach(this::printFinderType); 41 | return 0; 42 | } 43 | 44 | private int printFinderType(Finder.Type finderType) { 45 | sendFeedback("Finder " + finderType + " is set to [" + String.valueOf(FinderQueue.get().finderProfile.getActive(finderType)).toUpperCase() + "].", Formatting.AQUA,false); 46 | return 0; 47 | } 48 | 49 | private int setFinderCategory(Finder.Category finderCategory, boolean flag) { 50 | Finder.Type.getForCategory(finderCategory).forEach(finderType -> this.setFinderType(finderType, flag)); 51 | return 0; 52 | } 53 | 54 | private int setFinderType(Finder.Type finderType, boolean flag) { 55 | if(FinderQueue.get().finderProfile.setActive(finderType, flag)) { 56 | sendFeedback("Finder " + finderType + " has been set to [" + String.valueOf(flag).toUpperCase() + "].", Formatting.AQUA, false); 57 | } else { 58 | sendFeedback("Your current finder profile is locked and cannot be modified. Please make a copy first.", Formatting.RED, false); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/RenderCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcracker.finder.FinderQueue; 5 | import net.minecraft.server.command.ServerCommandSource; 6 | import net.minecraft.util.Formatting; 7 | 8 | import static net.minecraft.server.command.CommandManager.literal; 9 | 10 | public class RenderCommand extends ClientCommand { 11 | 12 | @Override 13 | public String getName() { 14 | return "render"; 15 | } 16 | 17 | @Override 18 | public void build(LiteralArgumentBuilder builder) { 19 | builder.then(literal("outlines") 20 | .executes(context -> this.printRenderMode()) 21 | ); 22 | 23 | for(FinderQueue.RenderType renderType: FinderQueue.RenderType.values()) { 24 | builder.then(literal("outlines") 25 | .then(literal(renderType.toString()).executes(context -> this.setRenderMode(renderType))) 26 | ); 27 | } 28 | } 29 | 30 | private int printRenderMode() { 31 | sendFeedback("Current render mode is set to [" + FinderQueue.get().renderType + "].", Formatting.AQUA, false); 32 | return 0; 33 | } 34 | 35 | private int setRenderMode(FinderQueue.RenderType renderType) { 36 | FinderQueue.get().renderType = renderType; 37 | sendFeedback("Set render mode to [" + FinderQueue.get().renderType + "].", Formatting.AQUA, false); 38 | return 0; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/command/VersionCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedutils.mc.MCVersion; 7 | import net.minecraft.server.command.ServerCommandSource; 8 | import net.minecraft.util.Formatting; 9 | 10 | import static net.minecraft.server.command.CommandManager.literal; 11 | 12 | public class VersionCommand extends ClientCommand { 13 | 14 | @Override 15 | public String getName() { 16 | return "version"; 17 | } 18 | 19 | @Override 20 | public void build(LiteralArgumentBuilder builder) { 21 | for(MCVersion version: MCVersion.values()) { 22 | if(version.isOlderThan(MCVersion.v1_13))continue; 23 | builder.then(literal(version.name).executes(context -> this.setVersion(version))); 24 | } 25 | } 26 | 27 | private int setVersion(MCVersion version) { 28 | SeedCracker.MC_VERSION = version; 29 | Features.init(SeedCracker.MC_VERSION); 30 | ClientCommand.sendFeedback("Changed version to " + version + ".", Formatting.AQUA, true); 31 | return 0; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker; 2 | 3 | import kaptainwutax.biomeutils.Biome; 4 | import kaptainwutax.biomeutils.source.BiomeSource; 5 | 6 | public class BiomeData { 7 | 8 | public final Biome biome; 9 | public final int x; 10 | public final int z; 11 | 12 | public BiomeData(Biome biome, int x, int z) { 13 | this.biome = biome; 14 | this.x = x; 15 | this.z = z; 16 | } 17 | 18 | public boolean test(BiomeSource source) { 19 | return source.getBiomeForNoiseGen(this.x, 0, this.z) == this.biome; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if(this == o) return true; 25 | if(!(o instanceof BiomeData))return false; 26 | BiomeData data = (BiomeData)o; 27 | return this.biome == data.biome; 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | return this.biome.getName().hashCode(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/DataAddedEvent.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker; 2 | 3 | import kaptainwutax.seedcracker.cracker.storage.DataStorage; 4 | import kaptainwutax.seedcracker.cracker.storage.TimeMachine; 5 | 6 | @FunctionalInterface 7 | public interface DataAddedEvent { 8 | 9 | DataAddedEvent POKE_PILLARS = s -> s.getTimeMachine().poke(TimeMachine.Phase.PILLARS); 10 | DataAddedEvent POKE_STRUCTURES = s -> s.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); 11 | DataAddedEvent POKE_BIOMES = s -> s.getTimeMachine().poke(TimeMachine.Phase.BIOMES); 12 | 13 | void onDataAdded(DataStorage dataStorage); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/HashedSeedData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker; 2 | 3 | import kaptainwutax.seedutils.lcg.rand.JRand; 4 | import kaptainwutax.seedutils.mc.seed.WorldSeed; 5 | 6 | public class HashedSeedData { 7 | 8 | private final long hashedSeed; 9 | 10 | public HashedSeedData(long hashedSeed) { 11 | this.hashedSeed = hashedSeed; 12 | } 13 | 14 | public boolean test(long seed, JRand rand) { 15 | return WorldSeed.toHash(seed) == this.hashedSeed; 16 | } 17 | 18 | public long getHashedSeed() { 19 | return this.hashedSeed; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | public class PillarData { 9 | 10 | private List heights; 11 | 12 | public PillarData(List heights) { 13 | this.heights = heights; 14 | } 15 | 16 | public boolean test(long seed) { 17 | List h = this.getPillarHeights((int)seed); 18 | return h.equals(this.heights); 19 | } 20 | 21 | public List getPillarHeights(int pillarSeed) { 22 | List indices = new ArrayList<>(); 23 | 24 | for(int i = 0; i < 10; i++) { 25 | indices.add(i); 26 | } 27 | 28 | Collections.shuffle(indices, new Random(pillarSeed)); 29 | 30 | List heights = new ArrayList<>(); 31 | 32 | for(Integer index : indices) { 33 | heights.add(76 + index * 3); 34 | } 35 | 36 | return heights; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/decorator/Decorator.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.decorator; 2 | 3 | import kaptainwutax.biomeutils.Biome; 4 | import kaptainwutax.biomeutils.source.BiomeSource; 5 | import kaptainwutax.featureutils.Feature; 6 | import kaptainwutax.seedutils.mc.ChunkRand; 7 | import kaptainwutax.seedutils.mc.MCVersion; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | public abstract class Decorator> extends Feature { 13 | 14 | public Decorator(C config, MCVersion version) { 15 | super(config, version); 16 | } 17 | 18 | public int getIndex(Biome biome) { 19 | return this.getConfig().getSalt(biome) % 10000; 20 | } 21 | 22 | public int getStep(Biome biome) { 23 | return this.getConfig().getSalt(biome) / 10000; 24 | } 25 | 26 | @Override 27 | public boolean canStart(D data, long structureSeed, ChunkRand rand) { 28 | rand.setDecoratorSeed(structureSeed, data.chunkX << 4, data.chunkZ << 4, 29 | this.getIndex(data.biome), this.getStep(data.biome), this.getVersion()); 30 | return true; 31 | } 32 | 33 | @Override 34 | public final boolean canSpawn(D data, BiomeSource source) { 35 | return this.canSpawn(data.chunkX, data.chunkZ, source); 36 | } 37 | 38 | public boolean canSpawn(int chunkX, int chunkZ, BiomeSource source) { 39 | if(this.getVersion().isOlderThan(MCVersion.v1_16)) { 40 | return this.isValidBiome(source.getBiome((chunkX << 4) + 8, 0, (chunkZ << 4) + 8)); 41 | } 42 | 43 | return this.isValidBiome(source.getBiomeForNoiseGen((chunkX << 2) + 2, 0, (chunkZ << 2) + 2)); 44 | } 45 | 46 | public abstract boolean isValidBiome(Biome biome); 47 | 48 | public static class Config extends Feature.Config { 49 | public final int defaultSalt; 50 | public final Map salts = new HashMap<>(); 51 | 52 | public Config(int step, int index) { 53 | this.defaultSalt = step * 10000 + index; 54 | } 55 | 56 | public Config add(int step, int index, Biome... biomes) { 57 | for(Biome biome: biomes) { 58 | this.salts.put(biome, step * 10000 + index); 59 | } 60 | 61 | return this; 62 | } 63 | 64 | public int getSalt(Biome biome) { 65 | return this.salts.getOrDefault(biome, this.defaultSalt); 66 | } 67 | } 68 | 69 | public static class Data> extends Feature.Data { 70 | public final Biome biome; 71 | 72 | public Data(T feature, int chunkX, int chunkZ, Biome biome) { 73 | super(feature, chunkX, chunkZ); 74 | this.biome = biome; 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/decorator/Dungeon.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.decorator; 2 | 3 | import kaptainwutax.biomeutils.Biome; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import kaptainwutax.seedcracker.cracker.storage.DataStorage; 6 | import kaptainwutax.seedcracker.cracker.storage.TimeMachine; 7 | import kaptainwutax.seedcracker.util.Log; 8 | import kaptainwutax.seedutils.lcg.LCG; 9 | import kaptainwutax.seedutils.mc.ChunkRand; 10 | import kaptainwutax.seedutils.mc.Dimension; 11 | import kaptainwutax.seedutils.mc.MCVersion; 12 | import kaptainwutax.seedutils.mc.VersionMap; 13 | import mjtb49.hashreversals.ChunkRandomReverser; 14 | import net.minecraft.util.math.Vec3i; 15 | import randomreverser.call.java.FilteredSkip; 16 | import randomreverser.call.java.NextInt; 17 | import randomreverser.device.JavaRandomDevice; 18 | import randomreverser.device.LCGReverserDevice; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Set; 22 | import java.util.stream.Collectors; 23 | 24 | public class Dungeon extends Decorator { 25 | 26 | public static final VersionMap CONFIGS = new VersionMap() 27 | .add(MCVersion.v1_13, new Decorator.Config(2, 3)) 28 | .add(MCVersion.v1_16, new Decorator.Config(3, 2) 29 | .add(3, 3, Biome.DESERT, Biome.SWAMP, Biome.SWAMP_HILLS)); 30 | 31 | public Dungeon(MCVersion version) { 32 | super(CONFIGS.getAsOf(version), version); 33 | } 34 | 35 | public Dungeon(Decorator.Config config) { 36 | super(config, null); 37 | } 38 | 39 | @Override 40 | public String getName() { 41 | return "dungeon"; 42 | } 43 | 44 | @Override 45 | public boolean canStart(Dungeon.Data data, long structureSeed, ChunkRand rand) { 46 | super.canStart(data, structureSeed, rand); 47 | 48 | for(int i = 0; i < 8; i++) { 49 | int x, y, z; 50 | 51 | if(this.getVersion().isOlderThan(MCVersion.v1_15)) { 52 | x = rand.nextInt(16); 53 | y = rand.nextInt(256); 54 | z = rand.nextInt(16); 55 | } else { 56 | x = rand.nextInt(16); 57 | z = rand.nextInt(16); 58 | y = rand.nextInt(256); 59 | } 60 | 61 | if(y == data.blockY && x == data.offsetX && z == data.offsetZ) { 62 | return true; 63 | } 64 | 65 | rand.nextInt(2); 66 | rand.nextInt(2); 67 | } 68 | 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean isValidDimension(Dimension dimension) { 74 | return dimension == Dimension.OVERWORLD; 75 | } 76 | 77 | @Override 78 | public boolean isValidBiome(Biome biome) { 79 | return biome != Biome.NETHER_WASTES && biome != Biome.SOUL_SAND_VALLEY && biome != Biome.WARPED_FOREST 80 | && biome != Biome.CRIMSON_FOREST && biome != Biome.BASALT_DELTAS && biome != Biome.END_MIDLANDS 81 | && biome != Biome.END_HIGHLANDS && biome != Biome.END_BARRENS && biome != Biome.SMALL_END_ISLANDS 82 | && biome != Biome.THE_VOID && biome == Biome.THE_END; 83 | } 84 | 85 | public Dungeon.Data at(int blockX, int blockY, int blockZ, Vec3i size, int[] floorCalls, Biome biome) { 86 | return new Dungeon.Data(this, blockX, blockY, blockZ, size, floorCalls, biome); 87 | } 88 | 89 | public static class Data extends Decorator.Data { 90 | public static final int COBBLESTONE_CALL = 0; 91 | public static final int MOSSY_COBBLESTONE_CALL = 1; 92 | public static final float MIN_FLOOR_BITS = 26.0F; 93 | public static final float MAX_FLOOR_BITS = 48.0F; 94 | 95 | public final int offsetX; 96 | private final int blockY; 97 | public final int offsetZ; 98 | public final Vec3i size; 99 | public final int[] floorCalls; 100 | public float bitsCount; 101 | 102 | public Data(Dungeon feature, int blockX, int blockY, int blockZ, Vec3i size, int[] floorCalls, Biome biome) { 103 | super(feature, blockX >> 4, blockZ >> 4, biome); 104 | this.offsetX = blockX & 15; 105 | this.blockY = blockY; 106 | this.offsetZ = blockZ & 15; 107 | this.size = size; 108 | this.floorCalls = floorCalls; 109 | 110 | if(floorCalls != null) { 111 | for(int call: floorCalls) { 112 | this.bitsCount += call == COBBLESTONE_CALL ? 2.0F : 0.0F; 113 | } 114 | } 115 | } 116 | 117 | public boolean usesFloor() { 118 | return this.bitsCount >= MIN_FLOOR_BITS && this.bitsCount <= MAX_FLOOR_BITS; 119 | } 120 | 121 | public void onDataAdded(DataStorage dataStorage) { 122 | dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); 123 | if(this.floorCalls == null || !this.usesFloor())return; 124 | if(dataStorage.getTimeMachine().structureSeeds != null)return; 125 | 126 | Log.warn("Short-cutting to dungeons..."); 127 | 128 | JavaRandomDevice device = new JavaRandomDevice(); 129 | 130 | if(this.feature.getVersion().isOlderThan(MCVersion.v1_15)) { 131 | device.addCall(NextInt.withValue(16, this.offsetX)); 132 | device.addCall(NextInt.withValue(256, this.blockY)); 133 | device.addCall(NextInt.withValue(16, this.offsetZ)); 134 | } else { 135 | device.addCall(NextInt.withValue(16, this.offsetX)); 136 | device.addCall(NextInt.withValue(16, this.offsetZ)); 137 | device.addCall(NextInt.withValue(256, this.blockY)); 138 | } 139 | 140 | device.addCall(NextInt.consume(2, 2)); //Skip size. 141 | 142 | for(int call: this.floorCalls) { 143 | if(call == COBBLESTONE_CALL) { 144 | device.addCall(NextInt.withValue(4, 0)); 145 | } else if(call == MOSSY_COBBLESTONE_CALL) { 146 | //Skip mossy, brute-force later. 147 | device.addCall(FilteredSkip.filter(LCG.JAVA, r -> r.nextInt(4) != 0, 1)); 148 | } 149 | } 150 | 151 | Set decoratorSeeds = device.streamSeeds(LCGReverserDevice.Process.EVERYTHING).sequential().limit(1).collect(Collectors.toSet()); 152 | 153 | if(decoratorSeeds.isEmpty()) { 154 | Log.error("Finished dungeon search with no seeds."); 155 | return; 156 | } 157 | 158 | dataStorage.getTimeMachine().structureSeeds = new ArrayList<>(); 159 | LCG failedDungeon = LCG.JAVA.combine(-5); 160 | 161 | for(long decoratorSeed: decoratorSeeds) { 162 | for(int i = 0; i < 8; i++) { 163 | ChunkRandomReverser.reversePopulationSeed((decoratorSeed ^ LCG.JAVA.multiplier) 164 | - this.feature.getConfig().getSalt(this.biome), 165 | this.chunkX << 4, this.chunkZ << 4, SeedCracker.MC_VERSION).forEach(structureSeed -> { 166 | Log.printSeed("Found structure seed ${SEED}.", structureSeed); 167 | dataStorage.getTimeMachine().structureSeeds.add(structureSeed); 168 | }); 169 | 170 | decoratorSeed = failedDungeon.nextSeed(decoratorSeed); 171 | } 172 | } 173 | 174 | dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES); 175 | } 176 | } 177 | 178 | } -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/decorator/EmeraldOre.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.decorator; 2 | 3 | import kaptainwutax.biomeutils.Biome; 4 | import kaptainwutax.seedutils.mc.ChunkRand; 5 | import kaptainwutax.seedutils.mc.Dimension; 6 | import kaptainwutax.seedutils.mc.MCVersion; 7 | import kaptainwutax.seedutils.mc.VersionMap; 8 | 9 | public class EmeraldOre extends Decorator { 10 | 11 | public static final VersionMap CONFIGS = new VersionMap() 12 | .add(MCVersion.v1_13, new Decorator.Config(4, 14)) 13 | .add(MCVersion.v1_16, new EmeraldOre.Config(6, 14)); 14 | 15 | public EmeraldOre(MCVersion version) { 16 | super(CONFIGS.getAsOf(version), version); 17 | } 18 | 19 | public EmeraldOre(Decorator.Config config) { 20 | super(config, null); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return "emerald_ore"; 26 | } 27 | 28 | @Override 29 | public boolean canStart(Data data, long structureSeed, ChunkRand rand) { 30 | super.canStart(data, structureSeed, rand); 31 | 32 | int bound = rand.nextInt(19) + 6; 33 | 34 | for(int i = 0; i < bound; i++) { 35 | int x, y, z; 36 | 37 | if(this.getVersion().isOlderThan(MCVersion.v1_15)) { 38 | x = rand.nextInt(16); 39 | y = rand.nextInt(28) + 4; 40 | z = rand.nextInt(16); 41 | } else { 42 | x = rand.nextInt(16); 43 | z = rand.nextInt(16); 44 | y = rand.nextInt(28) + 4; 45 | } 46 | 47 | if(y == data.blockY && x == data.offsetX && z == data.offsetZ) { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | @Override 56 | public boolean isValidDimension(Dimension dimension) { 57 | return dimension == Dimension.OVERWORLD; 58 | } 59 | 60 | @Override 61 | public boolean isValidBiome(Biome biome) { 62 | return biome == Biome.GRAVELLY_MOUNTAINS || biome == Biome.MODIFIED_GRAVELLY_MOUNTAINS 63 | || biome == Biome.MOUNTAINS || biome == Biome.WOODED_MOUNTAINS || biome == Biome.MOUNTAIN_EDGE; 64 | } 65 | 66 | public EmeraldOre.Data at(int blockX, int blockY, int blockZ, Biome biome) { 67 | return new EmeraldOre.Data(this, blockX, blockY, blockZ, biome); 68 | } 69 | 70 | public static class Data extends Decorator.Data { 71 | public final int offsetX; 72 | public final int blockY; 73 | public final int offsetZ; 74 | 75 | public Data(EmeraldOre feature, int blockX, int blockY, int blockZ, Biome biome) { 76 | super(feature, blockX >> 4, blockZ >> 4, biome); 77 | this.offsetX = blockX & 15; 78 | this.blockY = blockY; 79 | this.offsetZ = blockZ & 15; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/storage/DataStorage.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.storage; 2 | 3 | import io.netty.util.internal.ConcurrentSet; 4 | import kaptainwutax.featureutils.Feature; 5 | import kaptainwutax.featureutils.decorator.DesertWell; 6 | import kaptainwutax.featureutils.decorator.EndGateway; 7 | import kaptainwutax.featureutils.structure.BuriedTreasure; 8 | import kaptainwutax.featureutils.structure.Structure; 9 | import kaptainwutax.featureutils.structure.TriangularStructure; 10 | import kaptainwutax.featureutils.structure.UniformStructure; 11 | import kaptainwutax.seedcracker.cracker.BiomeData; 12 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 13 | import kaptainwutax.seedcracker.cracker.HashedSeedData; 14 | import kaptainwutax.seedcracker.cracker.PillarData; 15 | import kaptainwutax.seedcracker.cracker.decorator.Dungeon; 16 | import kaptainwutax.seedcracker.cracker.decorator.EmeraldOre; 17 | 18 | import java.util.Comparator; 19 | import java.util.Set; 20 | import java.util.function.Consumer; 21 | 22 | public class DataStorage { 23 | 24 | public static final Comparator>> SEED_DATA_COMPARATOR = (s1, s2) -> { 25 | boolean isStructure1 = s1.data.feature instanceof Structure; 26 | boolean isStructure2 = s2.data.feature instanceof Structure; 27 | 28 | //Structures always come before decorators. 29 | if(isStructure1 != isStructure2) { 30 | return isStructure2 ? 1: -1; 31 | } 32 | 33 | if(s1.equals(s2)) { 34 | return 0; 35 | } 36 | 37 | double diff = getBits(s2.data.feature) - getBits(s1.data.feature); 38 | return diff == 0 ? 1 : (int)Math.signum(diff); 39 | }; 40 | 41 | protected TimeMachine timeMachine = new TimeMachine(this); 42 | protected Set> scheduledData = new ConcurrentSet<>(); 43 | 44 | protected PillarData pillarData = null; 45 | protected ScheduledSet>> baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR); 46 | protected ScheduledSet> biomeSeedData = new ScheduledSet<>(null); 47 | protected HashedSeedData hashedSeedData = null; 48 | 49 | public void tick() { 50 | if(!this.timeMachine.isRunning) { 51 | this.baseSeedData.dump(); 52 | this.biomeSeedData.dump(); 53 | 54 | this.timeMachine.isRunning = true; 55 | 56 | TimeMachine.SERVICE.submit(() -> { 57 | try { 58 | this.scheduledData.removeIf(c -> { 59 | c.accept(this); 60 | return true; 61 | }); 62 | } catch(Exception e) { 63 | e.printStackTrace(); 64 | } 65 | 66 | this.timeMachine.isRunning = false; 67 | }); 68 | } 69 | } 70 | 71 | public synchronized boolean addPillarData(PillarData data, DataAddedEvent event) { 72 | boolean isAdded = this.pillarData == null; 73 | 74 | if(isAdded && data != null) { 75 | this.pillarData = data; 76 | this.schedule(event::onDataAdded); 77 | } 78 | 79 | return isAdded; 80 | } 81 | 82 | public synchronized boolean addBaseData(Feature.Data data, DataAddedEvent event) { 83 | Entry> e = new Entry<>(data, event); 84 | 85 | if(this.baseSeedData.contains(e)) { 86 | return false; 87 | } 88 | 89 | this.baseSeedData.scheduleAdd(e); 90 | this.schedule(event::onDataAdded); 91 | return true; 92 | } 93 | 94 | public synchronized boolean addBiomeData(BiomeData data, DataAddedEvent event) { 95 | Entry e = new Entry<>(data, event); 96 | 97 | if(this.biomeSeedData.contains(e)) { 98 | return false; 99 | } 100 | 101 | this.biomeSeedData.scheduleAdd(e); 102 | this.schedule(event::onDataAdded); 103 | return true; 104 | } 105 | 106 | public synchronized boolean addHashedSeedData(HashedSeedData data, DataAddedEvent event) { 107 | if(this.hashedSeedData == null || this.hashedSeedData.getHashedSeed() != data.getHashedSeed()) { 108 | this.hashedSeedData = data; 109 | this.schedule(event::onDataAdded); 110 | return true; 111 | } 112 | 113 | return false; 114 | } 115 | 116 | public void schedule(Consumer consumer) { 117 | this.scheduledData.add(consumer); 118 | } 119 | 120 | public TimeMachine getTimeMachine() { 121 | return this.timeMachine; 122 | } 123 | 124 | public double getBaseBits() { 125 | double bits = 0.0D; 126 | 127 | for(Entry> e: this.baseSeedData) { 128 | bits += getBits(e.data.feature); 129 | } 130 | 131 | return bits; 132 | } 133 | 134 | public double getWantedBits() { 135 | return 32.0D; 136 | } 137 | 138 | public static double getBits(Feature feature) { 139 | if(feature instanceof UniformStructure) { 140 | UniformStructure s = (UniformStructure)feature; 141 | return Math.log(s.getOffset() * s.getOffset()) / Math.log(2); 142 | } else if(feature instanceof TriangularStructure) { 143 | TriangularStructure s = (TriangularStructure)feature; 144 | return Math.log(s.getPeak() * s.getPeak()) / Math.log(2); 145 | } 146 | 147 | if(feature instanceof BuriedTreasure)return Math.log(100) / Math.log(2); 148 | if(feature instanceof DesertWell)return Math.log(1000 * 16 * 16) / Math.log(2); 149 | if(feature instanceof Dungeon)return Math.log(256 * 16 * 16 * 0.125D) / Math.log(2); 150 | if(feature instanceof EmeraldOre)return Math.log(28 * 16 * 16 * 0.5D) / Math.log(2); 151 | if(feature instanceof EndGateway)return Math.log(700 * 16 * 16 * 7) / Math.log(2); 152 | 153 | throw new UnsupportedOperationException("go do implement bits count for " + feature.getName() + " you fool"); 154 | } 155 | 156 | public void clear() { 157 | this.scheduledData = new ConcurrentSet<>(); 158 | this.pillarData = null; 159 | this.baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR); 160 | this.biomeSeedData = new ScheduledSet<>(null); 161 | this.hashedSeedData = null; 162 | this.timeMachine.shouldTerminate = true; 163 | this.timeMachine = new TimeMachine(this); 164 | } 165 | 166 | public static class Entry { 167 | public final T data; 168 | public final DataAddedEvent event; 169 | 170 | public Entry(T data, DataAddedEvent event) { 171 | this.data = data; 172 | this.event = event; 173 | } 174 | 175 | @Override 176 | public boolean equals(Object o) { 177 | if(this == o)return true; 178 | if(!(o instanceof Entry))return false; 179 | Entry entry = (Entry)o; 180 | 181 | if(this.data instanceof Feature.Data && entry.data instanceof Feature.Data) { 182 | Feature.Data d1 = (Feature.Data)this.data; 183 | Feature.Data d2 = (Feature.Data)entry.data; 184 | return d1.feature == d2.feature && d1.chunkX == d2.chunkX && d1.chunkZ == d2.chunkZ; 185 | } else if(this.data instanceof BiomeData && entry.data instanceof BiomeData) { 186 | return this.data.equals(entry.data); 187 | } 188 | 189 | return false; 190 | } 191 | 192 | @Override 193 | public int hashCode() { 194 | if(this.data instanceof Feature.Data) { 195 | return ((Feature.Data)this.data).chunkX * 31 + ((Feature.Data)this.data).chunkZ; 196 | } else if(this.data instanceof BiomeData) { 197 | return this.data.hashCode(); 198 | } 199 | 200 | return super.hashCode(); 201 | } 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/storage/ProgressListener.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.storage; 2 | 3 | import kaptainwutax.seedcracker.util.Log; 4 | 5 | public class ProgressListener { 6 | 7 | protected float progress; 8 | protected int count = 0; 9 | 10 | public ProgressListener() { 11 | this(0.0F); 12 | } 13 | 14 | public ProgressListener(float progress) { 15 | this.progress = progress; 16 | } 17 | 18 | public synchronized void addPercent(float percent, boolean debug) { 19 | if((this.count & 3) == 0 && debug) { 20 | Log.debug("Progress: " + this.progress + "%"); 21 | } 22 | 23 | this.count++; 24 | this.progress += percent; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/storage/ScheduledSet.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.storage; 2 | 3 | import java.util.*; 4 | 5 | public class ScheduledSet implements Iterable { 6 | 7 | protected final Set baseSet; 8 | protected final Set scheduledSet; 9 | 10 | public ScheduledSet(Comparator comparator) { 11 | if(comparator != null) { 12 | this.baseSet = new TreeSet<>(comparator); 13 | } else { 14 | this.baseSet = new HashSet<>(); 15 | } 16 | 17 | this.scheduledSet = new HashSet<>(); 18 | } 19 | 20 | public synchronized void scheduleAdd(T e) { 21 | this.scheduledSet.add(e); 22 | } 23 | 24 | public synchronized void dump() { 25 | synchronized(this.baseSet) { 26 | this.baseSet.addAll(this.scheduledSet); 27 | this.scheduledSet.clear(); 28 | } 29 | } 30 | 31 | public synchronized boolean contains(T e) { 32 | return this.baseSet.contains(e) || this.scheduledSet.contains(e); 33 | } 34 | 35 | public Set getBaseSet() { 36 | return this.baseSet; 37 | } 38 | 39 | @Override 40 | public synchronized Iterator iterator() { 41 | return this.baseSet.iterator(); 42 | } 43 | 44 | public synchronized int size() { 45 | return this.baseSet.size(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/cracker/storage/TimeMachine.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.cracker.storage; 2 | 3 | import kaptainwutax.biomeutils.source.OverworldBiomeSource; 4 | import kaptainwutax.featureutils.Feature; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.BiomeData; 7 | import kaptainwutax.seedcracker.util.Log; 8 | import kaptainwutax.seedutils.lcg.LCG; 9 | import kaptainwutax.seedutils.mc.ChunkRand; 10 | import kaptainwutax.seedutils.mc.seed.WorldSeed; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.concurrent.ExecutorService; 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | 18 | public class TimeMachine { 19 | 20 | public static ExecutorService SERVICE = Executors.newFixedThreadPool(5); 21 | 22 | private LCG inverseLCG = LCG.JAVA.combine(-2); 23 | protected DataStorage dataStorage; 24 | 25 | public boolean isRunning = false; 26 | public boolean shouldTerminate = false; 27 | 28 | public List pillarSeeds = null; 29 | public List structureSeeds = null; 30 | public List worldSeeds = null; 31 | 32 | public TimeMachine(DataStorage dataStorage) { 33 | this.dataStorage = dataStorage; 34 | } 35 | 36 | public void poke(Phase phase) { 37 | this.isRunning = true; 38 | 39 | final Phase[] finalPhase = {phase}; 40 | 41 | while(finalPhase[0] != null && !this.shouldTerminate) { 42 | if(finalPhase[0] == Phase.PILLARS) { 43 | if(!this.pokePillars())break; 44 | } else if(finalPhase[0] == Phase.STRUCTURES) { 45 | if(!this.pokeStructures())break; 46 | } else if(finalPhase[0] == Phase.BIOMES) { 47 | if(!this.pokeBiomes())break; 48 | } 49 | 50 | finalPhase[0] = finalPhase[0].nextPhase(); 51 | } 52 | } 53 | 54 | protected boolean pokePillars() { 55 | if(this.pillarSeeds != null || this.dataStorage.pillarData == null)return false; 56 | this.pillarSeeds = new ArrayList<>(); 57 | 58 | Log.debug("===================================="); 59 | Log.warn("Looking for pillar seeds..."); 60 | 61 | for(int pillarSeed = 0; pillarSeed < 1 << 16 && !this.shouldTerminate; pillarSeed++) { 62 | if(this.dataStorage.pillarData.test(pillarSeed)) { 63 | Log.printSeed("Found pillar seed ${SEED}.", pillarSeed); 64 | this.pillarSeeds.add(pillarSeed); 65 | } 66 | } 67 | 68 | if(!this.pillarSeeds.isEmpty()) { 69 | Log.warn("Finished searching for pillar seeds."); 70 | } else { 71 | Log.error("Finished search with no results."); 72 | } 73 | 74 | return true; 75 | } 76 | 77 | protected boolean pokeStructures() { 78 | if(this.pillarSeeds == null || this.structureSeeds != null || 79 | this.dataStorage.getBaseBits() < this.dataStorage.getWantedBits())return false; 80 | 81 | this.structureSeeds = new ArrayList<>(); 82 | 83 | Feature.Data[] cache = new Feature.Data[this.dataStorage.baseSeedData.size()]; 84 | int id = 0; 85 | 86 | for(DataStorage.Entry> entry: this.dataStorage.baseSeedData) { 87 | cache[id++] = entry.data; 88 | } 89 | 90 | for(int pillarSeed: this.pillarSeeds) { 91 | Log.debug("===================================="); 92 | Log.warn("Looking for structure seeds with pillar seed [" + pillarSeed + "]..."); 93 | 94 | AtomicInteger completion = new AtomicInteger(); 95 | ProgressListener progressListener = new ProgressListener(); 96 | 97 | for(int threadId = 0; threadId < 4; threadId++) { 98 | int fThreadId = threadId; 99 | 100 | SERVICE.submit(() -> { 101 | ChunkRand rand = new ChunkRand(); 102 | 103 | long lower = (long)fThreadId * (1L << 30); 104 | long upper = (long)(fThreadId + 1) * (1L << 30); 105 | 106 | for(long partialWorldSeed = lower; partialWorldSeed < upper && !this.shouldTerminate; partialWorldSeed++) { 107 | if((partialWorldSeed & ((1 << 27) - 1)) == 0) { 108 | progressListener.addPercent(3.125F, true); 109 | } 110 | 111 | long seed = this.timeMachine(partialWorldSeed, pillarSeed); 112 | 113 | boolean matches = true; 114 | 115 | for(Feature.Data baseSeedDatum: cache) { 116 | if(!baseSeedDatum.testStart(seed, rand)) { 117 | matches = false; 118 | break; 119 | } 120 | } 121 | 122 | if(matches) { 123 | this.structureSeeds.add(seed); 124 | Log.printSeed("Found structure seed ${SEED}.", seed); 125 | } 126 | } 127 | 128 | completion.getAndIncrement(); 129 | }); 130 | } 131 | 132 | while(completion.get() != 4) { 133 | try {Thread.sleep(50);} 134 | catch(InterruptedException e) {e.printStackTrace();} 135 | 136 | if(this.shouldTerminate) { 137 | return false; 138 | } 139 | } 140 | 141 | progressListener.addPercent(0.0F, true); 142 | } 143 | 144 | if(!this.structureSeeds.isEmpty()) { 145 | Log.warn("Finished searching for structure seeds."); 146 | } else { 147 | Log.error("Finished search with no results."); 148 | } 149 | 150 | return true; 151 | } 152 | 153 | protected boolean pokeBiomes() { 154 | if(this.structureSeeds == null || this.worldSeeds != null)return false; 155 | if(this.dataStorage.hashedSeedData == null && 156 | (this.dataStorage.biomeSeedData.size() < 5 || this.structureSeeds.size() > 20))return false; 157 | 158 | this.worldSeeds = new ArrayList<>(); 159 | Log.debug("===================================="); 160 | 161 | if(this.dataStorage.hashedSeedData != null) { 162 | Log.warn("Looking for world seeds..."); 163 | 164 | for(long structureSeed: this.structureSeeds) { 165 | WorldSeed.fromHash(structureSeed, this.dataStorage.hashedSeedData.getHashedSeed()).forEach(worldSeed -> { 166 | this.worldSeeds.add(worldSeed); 167 | Log.printSeed("Found world seed ${SEED}.", worldSeed); 168 | }); 169 | 170 | if(this.shouldTerminate) { 171 | return false; 172 | } 173 | } 174 | 175 | if(!this.worldSeeds.isEmpty()) { 176 | Log.warn("Finished searching for world seeds."); 177 | return true; 178 | } else { 179 | Log.error("Finished search with no results, reverting back to biomes."); 180 | } 181 | } 182 | 183 | Log.warn("Looking for world seeds..."); 184 | 185 | for(long structureSeed : this.structureSeeds) { 186 | for(long upperBits = 0; upperBits < 1 << 16 && !this.shouldTerminate; upperBits++) { 187 | long worldSeed = (upperBits << 48) | structureSeed; 188 | 189 | OverworldBiomeSource source = new OverworldBiomeSource(SeedCracker.MC_VERSION, worldSeed); 190 | 191 | boolean matches = true; 192 | 193 | for(DataStorage.Entry e: this.dataStorage.biomeSeedData) { 194 | if(!e.data.test(source)) { 195 | matches = false; 196 | break; 197 | } 198 | } 199 | 200 | if(matches) { 201 | this.worldSeeds.add(worldSeed); 202 | Log.printSeed("Found world seed ${SEED}.", worldSeed); 203 | } 204 | 205 | if(this.shouldTerminate) { 206 | return false; 207 | } 208 | } 209 | } 210 | 211 | if(!this.worldSeeds.isEmpty()) { 212 | Log.warn("Finished searching for world seeds."); 213 | } else { 214 | Log.error("Finished search with no results."); 215 | } 216 | 217 | return true; 218 | } 219 | 220 | public long timeMachine(long partialWorldSeed, int pillarSeed) { 221 | long currentSeed = 0L; 222 | currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16; 223 | currentSeed |= (long)pillarSeed << 16; 224 | currentSeed |= partialWorldSeed & 0xFFFFL; 225 | 226 | currentSeed = this.inverseLCG.nextSeed(currentSeed); 227 | currentSeed ^= LCG.JAVA.multiplier; 228 | return currentSeed; 229 | } 230 | 231 | public enum Phase { 232 | BIOMES(null), STRUCTURES(BIOMES), PILLARS(STRUCTURES); 233 | 234 | private final Phase nextPhase; 235 | 236 | Phase(Phase nextPhase) { 237 | this.nextPhase = nextPhase; 238 | } 239 | 240 | public Phase nextPhase() { 241 | return this.nextPhase; 242 | } 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder; 2 | 3 | import kaptainwutax.seedcracker.SeedCracker; 4 | import kaptainwutax.seedcracker.cracker.BiomeData; 5 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 6 | import kaptainwutax.seedcracker.render.Color; 7 | import kaptainwutax.seedcracker.render.Cube; 8 | import kaptainwutax.seedcracker.util.BiomeFixer; 9 | import net.minecraft.util.math.BlockPos; 10 | import net.minecraft.util.math.ChunkPos; 11 | import net.minecraft.world.Heightmap; 12 | import net.minecraft.world.World; 13 | import net.minecraft.world.biome.Biome; 14 | import net.minecraft.world.biome.BuiltinBiomes; 15 | import net.minecraft.world.dimension.DimensionType; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class BiomeFinder extends Finder { 21 | 22 | public BiomeFinder(World world, ChunkPos chunkPos) { 23 | super(world, chunkPos); 24 | } 25 | 26 | @Override 27 | public List findInChunk() { 28 | List result = new ArrayList<>(); 29 | 30 | for(int x = 0; x < 16; x += 4) { 31 | for(int z = 0; z < 16; z += 4) { 32 | BlockPos blockPos = this.chunkPos.getStartPos().add(x, 0, z); 33 | Biome biome = this.world.getBiomeForNoiseGen(blockPos.getX() >> 2, 0, blockPos.getZ() >> 2); 34 | 35 | //TODO: Fix this multi-threading issue. 36 | if(biome == BuiltinBiomes.THE_VOID) { 37 | continue; 38 | } 39 | 40 | kaptainwutax.biomeutils.Biome otherBiome = BiomeFixer.swap(biome); 41 | 42 | BiomeData data = new BiomeData(otherBiome, blockPos.getX() >> 2, blockPos.getZ() >> 2); 43 | 44 | if(SeedCracker.get().getDataStorage().addBiomeData(data, DataAddedEvent.POKE_BIOMES)) { 45 | blockPos = this.world.getTopPosition(Heightmap.Type.WORLD_SURFACE, blockPos).down(); 46 | result.add(blockPos); 47 | } 48 | } 49 | } 50 | 51 | result.forEach(pos -> { 52 | this.renderers.add(new Cube(pos, new Color(51, 204, 128))); 53 | }); 54 | 55 | return result; 56 | } 57 | 58 | @Override 59 | public boolean isValidDimension(DimensionType dimension) { 60 | return this.isOverworld(dimension); 61 | } 62 | 63 | public static List create(World world, ChunkPos chunkPos) { 64 | List finders = new ArrayList<>(); 65 | finders.add(new BiomeFinder(world, chunkPos)); 66 | return finders; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/BlockFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder; 2 | 3 | import net.minecraft.block.Block; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.util.math.BlockPos; 6 | import net.minecraft.util.math.ChunkPos; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.chunk.Chunk; 9 | 10 | import java.util.*; 11 | import java.util.stream.Collectors; 12 | 13 | public abstract class BlockFinder extends Finder { 14 | 15 | private Set targetBlockStates = new HashSet<>(); 16 | protected List searchPositions = new ArrayList<>(); 17 | 18 | public BlockFinder(World world, ChunkPos chunkPos, Block block) { 19 | super(world, chunkPos); 20 | this.targetBlockStates.addAll(block.getStateManager().getStates()); 21 | } 22 | 23 | public BlockFinder(World world, ChunkPos chunkPos, BlockState... blockStates) { 24 | super(world, chunkPos); 25 | this.targetBlockStates.addAll(Arrays.stream(blockStates).collect(Collectors.toList())); 26 | } 27 | 28 | @Override 29 | public List findInChunk() { 30 | List result = new ArrayList<>(); 31 | Chunk chunk = this.world.getChunk(this.chunkPos.getStartPos()); 32 | 33 | for(BlockPos blockPos: this.searchPositions) { 34 | BlockState currentState = chunk.getBlockState(blockPos); 35 | 36 | if(this.targetBlockStates.contains(currentState)) { 37 | result.add(this.chunkPos.getStartPos().add(blockPos)); 38 | } 39 | } 40 | 41 | return result; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/Finder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder; 2 | 3 | import kaptainwutax.seedcracker.finder.decorator.DesertWellFinder; 4 | import kaptainwutax.seedcracker.finder.decorator.DungeonFinder; 5 | import kaptainwutax.seedcracker.finder.decorator.EndGatewayFinder; 6 | import kaptainwutax.seedcracker.finder.decorator.EndPillarsFinder; 7 | import kaptainwutax.seedcracker.finder.decorator.ore.EmeraldOreFinder; 8 | import kaptainwutax.seedcracker.finder.structure.*; 9 | import kaptainwutax.seedcracker.render.Renderer; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.util.Identifier; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.util.math.ChunkPos; 14 | import net.minecraft.util.math.Vec3d; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.dimension.DimensionType; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | import java.util.function.Predicate; 22 | import java.util.stream.Collectors; 23 | 24 | public abstract class Finder { 25 | 26 | protected static final List CHUNK_POSITIONS = new ArrayList<>(); 27 | protected static final List SUB_CHUNK_POSITIONS = new ArrayList<>(); 28 | 29 | protected MinecraftClient mc = MinecraftClient.getInstance(); 30 | protected List renderers = new ArrayList<>(); 31 | protected World world; 32 | protected ChunkPos chunkPos; 33 | 34 | static { 35 | for(int x = 0; x < 16; x++) { 36 | for(int z = 0; z < 16; z++) { 37 | for(int y = 0; y < 256; y++) { 38 | BlockPos pos = new BlockPos(x, y, z); 39 | if(y < 16)SUB_CHUNK_POSITIONS.add(pos); 40 | CHUNK_POSITIONS.add(pos); 41 | } 42 | } 43 | } 44 | } 45 | 46 | public Finder(World world, ChunkPos chunkPos) { 47 | this.world = world; 48 | this.chunkPos = chunkPos; 49 | } 50 | 51 | public World getWorld() { 52 | return this.world; 53 | } 54 | 55 | public ChunkPos getChunkPos() { 56 | return this.chunkPos; 57 | } 58 | 59 | public abstract List findInChunk(); 60 | 61 | public boolean shouldRender() { 62 | DimensionType finderDim = this.world.getDimension(); 63 | DimensionType playerDim = mc.player.world.getDimension(); 64 | 65 | if(finderDim != playerDim)return false; 66 | 67 | int renderDistance = mc.options.viewDistance * 16 + 16; 68 | Vec3d playerPos = mc.player.getPos(); 69 | 70 | for(Renderer renderer: this.renderers) { 71 | BlockPos pos = renderer.getPos(); 72 | double distance = playerPos.squaredDistanceTo(pos.getX(), playerPos.y, pos.getZ()); 73 | if(distance <= renderDistance * renderDistance + 32)return true; 74 | } 75 | 76 | return false; 77 | } 78 | 79 | public void render() { 80 | this.renderers.forEach(Renderer::render); 81 | } 82 | 83 | public boolean isUseless() { 84 | return this.renderers.isEmpty(); 85 | } 86 | 87 | public abstract boolean isValidDimension(DimensionType dimension); 88 | 89 | public boolean isOverworld(DimensionType dimension) { 90 | return ((DimensionTypeCaller)dimension).getInfiniburn().getPath().endsWith("overworld"); 91 | } 92 | 93 | public boolean isNether(DimensionType dimension) { 94 | return ((DimensionTypeCaller)dimension).getInfiniburn().getPath().endsWith("nether"); 95 | } 96 | 97 | public boolean isEnd(DimensionType dimension) { 98 | return ((DimensionTypeCaller)dimension).getInfiniburn().getPath().endsWith("end"); 99 | } 100 | 101 | public static List buildSearchPositions(List base, Predicate removeIf) { 102 | List newList = new ArrayList<>(); 103 | 104 | for(BlockPos pos: base) { 105 | if(!removeIf.test(pos)) { 106 | newList.add(pos); 107 | } 108 | } 109 | 110 | return newList; 111 | } 112 | 113 | public enum Category { 114 | STRUCTURES, 115 | DECORATORS, 116 | BIOMES, 117 | } 118 | 119 | public enum Type { 120 | BURIED_TREASURE(BuriedTreasureFinder::create, Category.STRUCTURES), 121 | DESERT_TEMPLE(DesertPyramidFinder::create, Category.STRUCTURES), 122 | END_CITY(EndCityFinder::create, Category.STRUCTURES), 123 | //IGLOO(IglooFinder::create, Category.STRUCTURES), 124 | JUNGLE_TEMPLE(JunglePyramidFinder::create, Category.STRUCTURES), 125 | MONUMENT(MonumentFinder::create, Category.STRUCTURES), 126 | SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES), 127 | //MANSION(MansionFinder::create, Category.STRUCTURES), 128 | SHIPWRECK(ShipwreckFinder::create, Category.STRUCTURES), 129 | 130 | END_PILLARS(EndPillarsFinder::create, Category.DECORATORS), 131 | END_GATEWAY(EndGatewayFinder::create, Category.DECORATORS), 132 | DUNGEON(DungeonFinder::create, Category.DECORATORS), 133 | EMERALD_ORE(EmeraldOreFinder::create, Category.DECORATORS), 134 | DESERT_WELL(DesertWellFinder::create, Category.DECORATORS), 135 | BIOME(BiomeFinder::create, Category.BIOMES); 136 | 137 | public final FinderBuilder finderBuilder; 138 | private final Category category; 139 | 140 | Type(FinderBuilder finderBuilder, Category category) { 141 | this.finderBuilder = finderBuilder; 142 | this.category = category; 143 | } 144 | 145 | public static List getForCategory(Category category) { 146 | return Arrays.stream(values()).filter(type -> type.category == category).collect(Collectors.toList()); 147 | } 148 | } 149 | 150 | public interface DimensionTypeCaller { 151 | Identifier getInfiniburn(); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/FinderBuilder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder; 2 | 3 | import net.minecraft.util.math.ChunkPos; 4 | import net.minecraft.world.World; 5 | 6 | import java.util.List; 7 | 8 | @FunctionalInterface 9 | public interface FinderBuilder { 10 | 11 | List build(World world, ChunkPos chunkPos); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import kaptainwutax.seedcracker.profile.FinderConfig; 6 | import net.minecraft.client.render.GameRenderer; 7 | import net.minecraft.client.util.math.MatrixStack; 8 | import net.minecraft.util.math.ChunkPos; 9 | import net.minecraft.world.World; 10 | 11 | import java.util.List; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | 15 | public class FinderQueue { 16 | 17 | private final static FinderQueue INSTANCE = new FinderQueue(); 18 | public static ExecutorService SERVICE = Executors.newFixedThreadPool(5); 19 | 20 | public RenderType renderType = RenderType.XRAY; 21 | public FinderConfig finderProfile = new FinderConfig(); 22 | 23 | private FinderQueue() { 24 | this.clear(); 25 | } 26 | 27 | public static FinderQueue get() { 28 | return INSTANCE; 29 | } 30 | 31 | public void onChunkData(World world, ChunkPos chunkPos) { 32 | if(!SeedCracker.get().isActive())return; 33 | 34 | this.finderProfile.getActiveFinderTypes().forEach(type -> { 35 | SERVICE.submit(() -> { 36 | try { 37 | List finders = type.finderBuilder.build(world, chunkPos); 38 | 39 | finders.forEach(finder -> { 40 | if(finder.isValidDimension(world.getDimension())) { 41 | finder.findInChunk(); 42 | this.finderProfile.addFinder(type, finder); 43 | } 44 | }); 45 | } catch(Exception e) { 46 | e.printStackTrace(); 47 | } 48 | }); 49 | }); 50 | } 51 | 52 | public void renderFinders(MatrixStack matrices) { 53 | if(this.renderType == RenderType.OFF)return; 54 | 55 | MatrixStack matrixStack = RenderSystem.getModelViewStack(); 56 | 57 | matrixStack.push(); 58 | matrixStack.method_34425(matrices.peek().getModel()); 59 | RenderSystem.applyModelViewMatrix(); 60 | 61 | RenderSystem.setShader(GameRenderer::getPositionColorShader); 62 | RenderSystem.disableTexture(); 63 | RenderSystem.disableBlend(); 64 | 65 | //Makes it render through blocks. 66 | if(this.renderType == RenderType.XRAY) { 67 | RenderSystem.disableDepthTest(); 68 | } 69 | 70 | this.finderProfile.getActiveFinders().forEach(finder -> { 71 | if(finder.shouldRender()) { 72 | finder.render(); 73 | } 74 | }); 75 | 76 | matrixStack.pop(); 77 | RenderSystem.applyModelViewMatrix(); 78 | } 79 | 80 | public void clear() { 81 | this.renderType = RenderType.XRAY; 82 | this.finderProfile = new FinderConfig(); 83 | } 84 | 85 | public enum RenderType { 86 | OFF, ON, XRAY 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/DesertWellFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator; 2 | 3 | import kaptainwutax.featureutils.decorator.DesertWell; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.finder.structure.PieceFinder; 9 | import kaptainwutax.seedcracker.render.Color; 10 | import kaptainwutax.seedcracker.render.Cube; 11 | import kaptainwutax.seedcracker.render.Cuboid; 12 | import kaptainwutax.seedcracker.util.BiomeFixer; 13 | import net.minecraft.block.BlockState; 14 | import net.minecraft.block.Blocks; 15 | import net.minecraft.util.math.BlockPos; 16 | import net.minecraft.util.math.ChunkPos; 17 | import net.minecraft.util.math.Direction; 18 | import net.minecraft.util.math.Vec3i; 19 | import net.minecraft.world.World; 20 | import net.minecraft.world.biome.Biome; 21 | import net.minecraft.world.dimension.DimensionType; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class DesertWellFinder extends PieceFinder { 27 | 28 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 29 | return false; 30 | }); 31 | 32 | protected static Vec3i SIZE = new Vec3i(5, 6, 5); 33 | 34 | public DesertWellFinder(World world, ChunkPos chunkPos) { 35 | super(world, chunkPos, Direction.NORTH, SIZE); 36 | this.searchPositions = SEARCH_POSITIONS; 37 | this.buildStructure(); 38 | } 39 | 40 | @Override 41 | public List findInChunk() { 42 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 43 | 44 | if(!Features.DESERT_WELL.isValidBiome(BiomeFixer.swap(biome))) { 45 | return new ArrayList<>(); 46 | } 47 | 48 | List result = super.findInChunk(); 49 | 50 | result.forEach(pos -> { 51 | pos = pos.add(2, 1, 2); 52 | 53 | DesertWell.Data data = Features.DESERT_WELL.at(pos.getX(), pos.getZ()); 54 | 55 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 56 | this.renderers.add(new Cuboid(pos.add(-2, -1, -2), SIZE, new Color(128, 128, 255))); 57 | this.renderers.add(new Cube(pos, new Color(128, 128, 255))); 58 | } 59 | }); 60 | 61 | return result; 62 | } 63 | 64 | @Override 65 | public boolean isValidDimension(DimensionType dimension) { 66 | return this.isOverworld(dimension); 67 | } 68 | 69 | protected void buildStructure() { 70 | BlockState sandstone = Blocks.SANDSTONE.getDefaultState(); 71 | BlockState sandstoneSlab = Blocks.SANDSTONE_SLAB.getDefaultState(); 72 | BlockState water = Blocks.WATER.getDefaultState(); 73 | 74 | this.fillWithOutline(0, 0, 0, 4, 1, 4, sandstone, sandstone, false); 75 | this.fillWithOutline(1, 5, 1, 3, 5, 3, sandstoneSlab, sandstoneSlab, false); 76 | this.addBlock(sandstone, 2, 5, 2); 77 | 78 | BlockPos p1 = new BlockPos(2, 1, 2); 79 | this.addBlock(water, p1.getX(), p1.getY(), p1.getZ()); 80 | 81 | Direction.Type.HORIZONTAL.forEach(facing -> { 82 | BlockPos p2 = p1.offset(facing); 83 | this.addBlock(water, p2.getX(), p2.getY(), p2.getZ()); 84 | }); 85 | } 86 | 87 | public static List create(World world, ChunkPos chunkPos) { 88 | List finders = new ArrayList<>(); 89 | finders.add(new DesertWellFinder(world, chunkPos)); 90 | 91 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 92 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 93 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 94 | 95 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 96 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); 97 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); 98 | 99 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 100 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1))); 101 | return finders; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/DungeonFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator; 2 | 3 | import kaptainwutax.seedcracker.Features; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import kaptainwutax.seedcracker.cracker.decorator.Dungeon; 6 | import kaptainwutax.seedcracker.finder.BlockFinder; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import kaptainwutax.seedcracker.util.BiomeFixer; 12 | import kaptainwutax.seedcracker.util.PosIterator; 13 | import net.minecraft.block.Block; 14 | import net.minecraft.block.Blocks; 15 | import net.minecraft.block.entity.BlockEntity; 16 | import net.minecraft.block.entity.MobSpawnerBlockEntity; 17 | import net.minecraft.util.math.BlockPos; 18 | import net.minecraft.util.math.ChunkPos; 19 | import net.minecraft.util.math.Vec3i; 20 | import net.minecraft.world.World; 21 | import net.minecraft.world.biome.Biome; 22 | import net.minecraft.world.dimension.DimensionType; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.Set; 27 | 28 | public class DungeonFinder extends BlockFinder { 29 | 30 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 31 | return false; 32 | }); 33 | 34 | protected static Set REQUIRED_FLOOR_POSITIONS = PosIterator.create( 35 | new BlockPos(-3, -1, -3), 36 | new BlockPos(3, -1, 3) 37 | ); 38 | 39 | public DungeonFinder(World world, ChunkPos chunkPos) { 40 | super(world, chunkPos, Blocks.SPAWNER); 41 | this.searchPositions = SEARCH_POSITIONS; 42 | } 43 | 44 | @Override 45 | public List findInChunk() { 46 | //Gets all the positions with a mob spawner in the chunk. 47 | List result = super.findInChunk(); 48 | 49 | if(result.size() != 1)return new ArrayList<>(); 50 | 51 | result.removeIf(pos -> { 52 | BlockEntity blockEntity = this.world.getBlockEntity(pos); 53 | if(!(blockEntity instanceof MobSpawnerBlockEntity))return true; 54 | 55 | for(BlockPos blockPos: REQUIRED_FLOOR_POSITIONS) { 56 | BlockPos currentPos = pos.add(blockPos); 57 | Block currentBlock = this.world.getBlockState(currentPos).getBlock(); 58 | 59 | if(currentBlock == Blocks.COBBLESTONE) {} 60 | else if(currentBlock == Blocks.MOSSY_COBBLESTONE) {} 61 | else return true; 62 | } 63 | 64 | return false; 65 | }); 66 | 67 | if(result.size() != 1)return new ArrayList<>(); 68 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 69 | 70 | BlockPos pos = result.get(0); 71 | Vec3i size = this.getDungeonSize(pos); 72 | int[] floorCalls = this.getFloorCalls(size, pos); 73 | 74 | Dungeon.Data data = Features.DUNGEON.at(pos.getX(), pos.getY(), pos.getZ(), size, floorCalls, BiomeFixer.swap(biome)); 75 | 76 | if(SeedCracker.get().getDataStorage().addBaseData(data, data::onDataAdded)) { 77 | this.renderers.add(new Cube(pos, new Color(255, 0, 0))); 78 | 79 | if(data.usesFloor()) { 80 | this.renderers.add(new Cuboid(pos.subtract(size), pos.add(size).add(1, -1, 1), new Color(255, 0, 0))); 81 | } 82 | } 83 | 84 | return result; 85 | } 86 | 87 | public Vec3i getDungeonSize(BlockPos spawnerPos) { 88 | for(int xo = 4; xo >= 3; xo--) { 89 | for(int zo = 4; zo >= 3; zo--) { 90 | Block block = this.world.getBlockState(spawnerPos.add(xo, -1, zo)).getBlock(); 91 | if(block == Blocks.MOSSY_COBBLESTONE || block == Blocks.COBBLESTONE)return new Vec3i(xo, 0, zo); 92 | } 93 | } 94 | 95 | return Vec3i.ZERO; 96 | } 97 | 98 | public int[] getFloorCalls(Vec3i dungeonSize, BlockPos spawnerPos) { 99 | int[] floorCalls = new int[(dungeonSize.getX() * 2 + 1) * (dungeonSize.getZ() * 2 + 1)]; 100 | int i = 0; 101 | 102 | for(int xo = -dungeonSize.getX(); xo <= dungeonSize.getX(); xo++) { 103 | for(int zo = -dungeonSize.getZ(); zo <= dungeonSize.getZ(); zo++) { 104 | Block block = this.world.getBlockState(spawnerPos.add(xo, -1, zo)).getBlock(); 105 | 106 | if(block == Blocks.MOSSY_COBBLESTONE) { 107 | floorCalls[i++] = Dungeon.Data.MOSSY_COBBLESTONE_CALL; 108 | } else if(block == Blocks.COBBLESTONE) { 109 | floorCalls[i++] = Dungeon.Data.COBBLESTONE_CALL; 110 | } else { 111 | return null; 112 | } 113 | } 114 | } 115 | 116 | return floorCalls; 117 | } 118 | 119 | @Override 120 | public boolean isValidDimension(DimensionType dimension) { 121 | return this.isOverworld(dimension); 122 | } 123 | 124 | public static List create(World world, ChunkPos chunkPos) { 125 | List finders = new ArrayList<>(); 126 | finders.add(new DungeonFinder(world, chunkPos)); 127 | 128 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 129 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 130 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 131 | 132 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 133 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); 134 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); 135 | 136 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 137 | finders.add(new DungeonFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1))); 138 | return finders; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/EndGatewayFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator; 2 | 3 | import kaptainwutax.featureutils.decorator.EndGateway; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.BlockFinder; 8 | import kaptainwutax.seedcracker.finder.Finder; 9 | import kaptainwutax.seedcracker.render.Color; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import kaptainwutax.seedcracker.util.BiomeFixer; 12 | import net.minecraft.block.BlockState; 13 | import net.minecraft.block.Blocks; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.World; 17 | import net.minecraft.world.biome.Biome; 18 | import net.minecraft.world.dimension.DimensionType; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | public class EndGatewayFinder extends BlockFinder { 24 | 25 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 26 | return false; 27 | }); 28 | 29 | public EndGatewayFinder(World world, ChunkPos chunkPos) { 30 | super(world, chunkPos, Blocks.END_GATEWAY); 31 | this.searchPositions = SEARCH_POSITIONS; 32 | } 33 | 34 | @Override 35 | public List findInChunk() { 36 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 37 | if(!Features.END_GATEWAY.isValidBiome(BiomeFixer.swap(biome)))return new ArrayList<>(); 38 | 39 | List result = super.findInChunk(); 40 | List newResult = new ArrayList<>(); 41 | 42 | result.forEach(pos -> { 43 | int height = this.findHeight(pos); 44 | 45 | if(height >= 3 && height <= 9) { 46 | newResult.add(pos); 47 | 48 | EndGateway.Data data = Features.END_GATEWAY.at(pos.getX(), pos.getZ(), height); 49 | 50 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 51 | this.renderers.add(new Cuboid(pos.add(-1, -2, -1), pos.add(2, 3, 2), new Color(102, 102, 210))); 52 | } 53 | } 54 | }); 55 | 56 | return newResult; 57 | } 58 | 59 | private int findHeight(BlockPos pos) { 60 | int height = 0; 61 | 62 | while(pos.getY() >= 0) { 63 | pos = pos.down(); 64 | height++; 65 | 66 | BlockState state = this.world.getBlockState(pos); 67 | 68 | //Bedrock generates below gateways. 69 | if(state.getBlock() == Blocks.BEDROCK || state.getBlock() != Blocks.END_STONE) { 70 | continue; 71 | } 72 | 73 | break; 74 | } 75 | 76 | return height - 1; 77 | } 78 | 79 | @Override 80 | public boolean isValidDimension(DimensionType dimension) { 81 | return this.isEnd(dimension); 82 | } 83 | 84 | public static List create(World world, ChunkPos chunkPos) { 85 | List finders = new ArrayList<>(); 86 | finders.add(new EndGatewayFinder(world, chunkPos)); 87 | return finders; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/EndPillarsFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator; 2 | 3 | import kaptainwutax.seedcracker.SeedCracker; 4 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 5 | import kaptainwutax.seedcracker.cracker.PillarData; 6 | import kaptainwutax.seedcracker.finder.BlockFinder; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.util.math.ChunkPos; 13 | import net.minecraft.util.math.MathHelper; 14 | import net.minecraft.util.math.Vec3i; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.dimension.DimensionType; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.stream.Collectors; 21 | 22 | public class EndPillarsFinder extends Finder { 23 | 24 | private boolean alreadyFound; 25 | protected BedrockMarkerFinder[] bedrockMarkers = new BedrockMarkerFinder[10]; 26 | 27 | public EndPillarsFinder(World world, ChunkPos chunkPos) { 28 | super(world, chunkPos); 29 | 30 | this.alreadyFound = !SeedCracker.get().getDataStorage().addPillarData(null, DataAddedEvent.POKE_PILLARS); 31 | if(this.alreadyFound)return; 32 | 33 | for(int i = 0; i < this.bedrockMarkers.length; i++) { 34 | int x = MathHelper.floor(42.0D * Math.cos(2.0D * (-Math.PI + (Math.PI / 10.0D) * (double)i))); 35 | int z = MathHelper.floor(42.0D * Math.sin(2.0D * (-Math.PI + (Math.PI / 10.0D) * (double)i))); 36 | this.bedrockMarkers[i] = new BedrockMarkerFinder(this.world, new ChunkPos(new BlockPos(x, 0, z)), new BlockPos(x, 0, z)); 37 | } 38 | } 39 | 40 | @Override 41 | public List findInChunk() { 42 | List result = new ArrayList<>(); 43 | 44 | for(BedrockMarkerFinder bedrockMarker: this.bedrockMarkers) { 45 | if(bedrockMarker == null)continue; 46 | result.addAll(bedrockMarker.findInChunk()); 47 | } 48 | 49 | if(result.size() == this.bedrockMarkers.length) { 50 | PillarData pillarData = new PillarData(result.stream().map(Vec3i::getY).collect(Collectors.toList())); 51 | 52 | if(SeedCracker.get().getDataStorage().addPillarData(pillarData, DataAddedEvent.POKE_PILLARS)) { 53 | result.forEach(pos -> this.renderers.add(new Cube(pos, new Color(128, 0, 128)))); 54 | } 55 | 56 | } 57 | 58 | return result; 59 | } 60 | 61 | @Override 62 | public boolean isValidDimension(DimensionType dimension) { 63 | return this.isEnd(dimension); 64 | } 65 | 66 | public static List create(World world, ChunkPos chunkPos) { 67 | List finders = new ArrayList<>(); 68 | finders.add(new EndPillarsFinder(world, chunkPos)); 69 | return finders; 70 | } 71 | 72 | public static class BedrockMarkerFinder extends BlockFinder { 73 | 74 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 75 | if(pos.getY() < 76)return true; 76 | if(pos.getY() > 76 + 3 * 10)return true; 77 | return false; 78 | }); 79 | 80 | public BedrockMarkerFinder(World world, ChunkPos chunkPos, BlockPos xz) { 81 | super(world, chunkPos, Blocks.BEDROCK); 82 | this.searchPositions = SEARCH_POSITIONS; 83 | } 84 | 85 | @Override 86 | public List findInChunk() { 87 | return super.findInChunk(); 88 | } 89 | 90 | @Override 91 | public boolean isValidDimension(DimensionType dimension) { 92 | return true; 93 | } 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/OreFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator; 2 | 3 | import kaptainwutax.seedcracker.finder.BlockFinder; 4 | import kaptainwutax.seedcracker.util.PosIterator; 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.ChunkPos; 8 | import net.minecraft.world.World; 9 | import net.minecraft.world.dimension.DimensionType; 10 | import net.minecraft.world.gen.feature.OreFeatureConfig; 11 | 12 | import java.util.*; 13 | import java.util.stream.Collectors; 14 | 15 | public abstract class OreFinder extends BlockFinder { 16 | 17 | public static final int LOWEST = -1; 18 | public static final int HIGHEST = 1; 19 | 20 | protected OreFeatureConfig oreFeatureConfig; 21 | 22 | public OreFinder(World world, ChunkPos chunkPos, BlockState state) { 23 | //super(world, chunkPos, oreFeatureConfig.state); 24 | super(world, chunkPos, state); 25 | //this.oreFeatureConfig = oreFeatureConfig; 26 | } 27 | 28 | @Override 29 | public final List findInChunk() { 30 | List result = super.findInChunk(); 31 | List> veins = new ArrayList<>(); 32 | 33 | while(!result.isEmpty()) { 34 | Set vein = this.buildVeinRecursively(result.get(0), new HashSet<>()); 35 | vein.forEach(result::remove); 36 | veins.add(vein); 37 | } 38 | 39 | veins.removeIf(vein -> vein.size() > this.oreFeatureConfig.size); 40 | veins.removeIf(vein -> !this.isCompleteVein(vein)); 41 | 42 | this.findOreVeins(veins); 43 | return result; 44 | } 45 | 46 | public Set buildVeinRecursively(BlockPos start, Set progress) { 47 | progress.add(start); 48 | 49 | PosIterator.create(new BlockPos(-1, -1, -1), new BlockPos(1, 1, 1)).forEach(offset -> { 50 | BlockPos pos = start.add(offset); 51 | BlockState state = this.world.getBlockState(pos); 52 | 53 | /* 54 | if(!progress.contains(pos) && state.equals(this.oreFeatureConfig.state)) { 55 | this.buildVeinRecursively(pos, progress); 56 | }*/ 57 | }); 58 | 59 | return progress; 60 | } 61 | 62 | private boolean isCompleteVein(Set vein) { 63 | /* 64 | for(BlockPos pos: vein) { 65 | for(Direction direction: Direction.values()) { 66 | BlockState state = this.world.getBlockState(pos.offset(direction)); 67 | if(!state.equals(this.oreFeatureConfig.state) && 68 | !this.oreFeatureConfig.target.test(state, null))return false; 69 | } 70 | }*/ 71 | 72 | return true; 73 | } 74 | 75 | public boolean canVeinTo(BlockPos b1, BlockPos b2) { 76 | return Math.max(Math.max(Math.abs(b1.getX() - b2.getX()), Math.abs(b1.getY() - b2.getY())), Math.abs(b1.getZ() - b2.getZ())) <= 1; 77 | } 78 | 79 | public int findX(Set vein, int type) { 80 | return getInt(vein.stream().map(BlockPos::getX).collect(Collectors.toList()), type); 81 | } 82 | 83 | public int findY(Set vein, int type) { 84 | return getInt(vein.stream().map(BlockPos::getY).collect(Collectors.toList()), type); 85 | } 86 | 87 | public int findZ(Set vein, int type) { 88 | return getInt(vein.stream().map(BlockPos::getZ).collect(Collectors.toList()), type); 89 | } 90 | 91 | private int getInt(List ints, int type) { 92 | Collections.sort(ints); 93 | return ints.get(type == HIGHEST ? ints.size() - 1 : 0); 94 | } 95 | 96 | public abstract void findOreVeins(List> veins); 97 | 98 | @Override 99 | public boolean isValidDimension(DimensionType dimension) { 100 | return this.isOverworld(dimension); 101 | } 102 | 103 | /* 104 | public boolean method_13628(float piRand, int nextIntA, int nextIntB, BlockPos blockPos_1, OreFeatureConfig oreFeatureConfig_1) { 105 | float float_2 = (float)oreFeatureConfig_1.size / 8.0F; 106 | int int_1 = MathHelper.ceil(((float)oreFeatureConfig_1.size / 16.0F * 2.0F + 1.0F) / 2.0F); 107 | double double_1 = (float)blockPos_1.getX() + MathHelper.sin(piRand) * float_2; 108 | double double_2 = (float)blockPos_1.getX() - MathHelper.sin(piRand) * float_2; 109 | double double_3 = (float)blockPos_1.getZ() + MathHelper.cos(piRand) * float_2; 110 | double double_4 = (float)blockPos_1.getZ() - MathHelper.cos(piRand) * float_2; 111 | double double_5 = blockPos_1.getY() + nextIntA - 2; 112 | double double_6 = blockPos_1.getY() + nextIntB - 2; 113 | int int_3 = blockPos_1.getX() - MathHelper.ceil(float_2) - int_1; 114 | int int_4 = blockPos_1.getY() - 2 - int_1; 115 | int int_5 = blockPos_1.getZ() - MathHelper.ceil(float_2) - int_1; 116 | int int_6 = 2 * (MathHelper.ceil(float_2) + int_1); 117 | int int_7 = 2 * (2 + int_1); 118 | 119 | for(int int_8 = int_3; int_8 <= int_3 + int_6; ++int_8) { 120 | for(int int_9 = int_5; int_9 <= int_5 + int_6; ++int_9) { 121 | return this.generateVeinPart(oreFeatureConfig_1, double_1, double_2, double_3, double_4, double_5, double_6, int_3, int_4, int_5, int_6, int_7); 122 | } 123 | } 124 | 125 | return false; 126 | } 127 | 128 | protected boolean generateVeinPart(OreFeatureConfig oreConfig, double double_1, double double_2, double double_3, double double_4, double double_5, double double_6, int int_1, int int_2, int int_3, int int_4, int int_5) { 129 | int int_6 = 0; 130 | BitSet bitSet_1 = new BitSet(int_4 * int_5 * int_4); 131 | BlockPos.Mutable blockPos$Mutable_1 = new BlockPos.Mutable(); 132 | double[] oreData = new double[oreConfig.size * 4]; 133 | 134 | for(int genStep = 0; genStep < oreConfig.size; ++genStep) { 135 | float genStepProgress = (float)genStep / (float)oreConfig.size; 136 | double xOffset = double_1 + (double_2 - double_1) * genStepProgress; 137 | double yOffset = double_5 + (double_6 - double_5) * genStepProgress; 138 | double zOffset = double_3 + (double_4 - double_3) * genStepProgress; 139 | double genSizeMultiplier = random_1.nextDouble() * (double)oreConfig.size / 16.0D; 140 | double randomBoundOffset = ((double)(MathHelper.sin((float)(Math.PI * genStepProgress)) + 1.0F) * genSizeMultiplier + 1.0D) / 2.0D; 141 | oreData[genStep * 4 + 0] = xOffset; 142 | oreData[genStep * 4 + 1] = yOffset; 143 | oreData[genStep * 4 + 2] = zOffset; 144 | oreData[genStep * 4 + 3] = randomBoundOffset; 145 | } 146 | 147 | for(int genStep = 0; genStep < oreConfig.size - 1; ++genStep) { 148 | if (oreData[genStep * 4 + 3] > 0.0D) { 149 | for(int int_9 = genStep + 1; int_9 < oreConfig.size; ++int_9) { 150 | if (oreData[int_9 * 4 + 3] > 0.0D) { 151 | double xOffset = oreData[genStep * 4 + 0] - oreData[int_9 * 4 + 0]; 152 | double yOffset = oreData[genStep * 4 + 1] - oreData[int_9 * 4 + 1]; 153 | double zOffset = oreData[genStep * 4 + 2] - oreData[int_9 * 4 + 2]; 154 | double genSizeMultiplier = oreData[genStep * 4 + 3] - oreData[int_9 * 4 + 3]; 155 | if (genSizeMultiplier * genSizeMultiplier > xOffset * xOffset + yOffset * yOffset + zOffset * zOffset) { 156 | if (genSizeMultiplier > 0.0D) { 157 | oreData[int_9 * 4 + 3] = -1.0D; 158 | } else { 159 | oreData[genStep * 4 + 3] = -1.0D; 160 | } 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | for(int genStep = 0; genStep < oreConfig.size; ++genStep) { 168 | double randomBoundOffset = oreData[genStep * 4 + 3]; 169 | if (randomBoundOffset < 0.0D)continue; 170 | 171 | double xOffset = oreData[genStep * 4 + 0]; 172 | double yOffset = oreData[genStep * 4 + 1]; 173 | double zOffset = oreData[genStep * 4 + 2]; 174 | int lowerXbound = Math.max(MathHelper.floor(xOffset - randomBoundOffset), int_1); 175 | int lowerYbound = Math.max(MathHelper.floor(yOffset - randomBoundOffset), int_2); 176 | int lowerZbound = Math.max(MathHelper.floor(zOffset - randomBoundOffset), int_3); 177 | int upperXbound = Math.max(MathHelper.floor(xOffset + randomBoundOffset), lowerXbound); 178 | int upperYbound = Math.max(MathHelper.floor(yOffset + randomBoundOffset), lowerYbound); 179 | int upperZbound = Math.max(MathHelper.floor(zOffset + randomBoundOffset), lowerZbound); 180 | 181 | for(int attemptedPosX = lowerXbound; attemptedPosX <= upperXbound; ++attemptedPosX) { 182 | for(int attemptedPosY = lowerYbound; attemptedPosY <= upperYbound; ++attemptedPosY) { 183 | for(int attemptedPosZ = lowerZbound; attemptedPosZ <= upperZbound; ++attemptedPosZ) { 184 | double posX = ((double) attemptedPosX + 0.5D - xOffset) / randomBoundOffset; 185 | double posY = ((double) attemptedPosY + 0.5D - yOffset) / randomBoundOffset; 186 | double posZ = ((double) attemptedPosZ + 0.5D - zOffset) / randomBoundOffset; 187 | boolean posInUnitSphere = posX * posX + posY * posY + posZ * posZ < 1.0D; 188 | 189 | if(posInUnitSphere) { 190 | int int_20 = attemptedPosX - int_1 + (attemptedPosY - int_2) * int_4 + (attemptedPosZ - int_3) * int_4 * int_5; 191 | if (!bitSet_1.get(int_20)) { 192 | bitSet_1.set(int_20); 193 | blockPos$Mutable_1.set(attemptedPosX, attemptedPosY, attemptedPosZ); 194 | if (oreConfig.target.getCondition().test(iWorld_1.getBlockState(blockPos$Mutable_1))) { 195 | iWorld_1.setBlockState(blockPos$Mutable_1, oreConfig.state, 2); 196 | ++int_6; 197 | } 198 | } 199 | } 200 | } 201 | } 202 | } 203 | } 204 | 205 | return int_6 > 0; 206 | }*/ 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/decorator/ore/EmeraldOreFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.decorator.ore; 2 | 3 | import kaptainwutax.seedcracker.Features; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 6 | import kaptainwutax.seedcracker.cracker.decorator.EmeraldOre; 7 | import kaptainwutax.seedcracker.finder.BlockFinder; 8 | import kaptainwutax.seedcracker.finder.Finder; 9 | import kaptainwutax.seedcracker.render.Color; 10 | import kaptainwutax.seedcracker.render.Cube; 11 | import kaptainwutax.seedcracker.util.BiomeFixer; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.biome.Biome; 17 | import net.minecraft.world.dimension.DimensionType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class EmeraldOreFinder extends BlockFinder { 23 | 24 | protected static List SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> { 25 | if(pos.getY() < 4)return true; 26 | if(pos.getY() > 28 + 4)return true; 27 | return false; 28 | }); 29 | 30 | public EmeraldOreFinder(World world, ChunkPos chunkPos) { 31 | super(world, chunkPos, Blocks.EMERALD_ORE); 32 | this.searchPositions = SEARCH_POSITIONS; 33 | } 34 | 35 | @Override 36 | public List findInChunk() { 37 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 38 | 39 | List result = super.findInChunk(); 40 | if(result.isEmpty())return result; 41 | 42 | BlockPos pos = result.get(0); 43 | 44 | EmeraldOre.Data data = Features.EMERALD_ORE.at(pos.getX(), pos.getY(), pos.getZ(), BiomeFixer.swap(biome)); 45 | 46 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 47 | this.renderers.add(new Cube(pos, new Color(0, 255, 0))); 48 | } 49 | 50 | return result; 51 | } 52 | 53 | @Override 54 | public boolean isValidDimension(DimensionType dimension) { 55 | return this.isOverworld(dimension); 56 | } 57 | 58 | public static List create(World world, ChunkPos chunkPos) { 59 | List finders = new ArrayList<>(); 60 | finders.add(new EmeraldOreFinder(world, chunkPos)); 61 | return finders; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/AbstractTempleFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | import kaptainwutax.seedcracker.render.Color; 5 | import kaptainwutax.seedcracker.render.Cube; 6 | import kaptainwutax.seedcracker.render.Cuboid; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.ChunkPos; 9 | import net.minecraft.util.math.Direction; 10 | import net.minecraft.util.math.Vec3i; 11 | import net.minecraft.world.World; 12 | import net.minecraft.world.biome.Biome; 13 | import net.minecraft.world.dimension.DimensionType; 14 | import net.minecraft.world.gen.feature.StructureFeature; 15 | 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | public abstract class AbstractTempleFinder extends Finder { 22 | 23 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 24 | if(pos.getX() != 0)return true; 25 | if(pos.getY() < 63)return true; 26 | if(pos.getZ() != 0)return true; 27 | return false; 28 | }); 29 | 30 | protected List finders = new ArrayList<>(); 31 | protected final Vec3i size; 32 | 33 | public AbstractTempleFinder(World world, ChunkPos chunkPos, Vec3i size) { 34 | super(world, chunkPos); 35 | 36 | Direction.Type.HORIZONTAL.forEach(direction -> { 37 | PieceFinder finder = new PieceFinder(world, chunkPos, direction, size); 38 | 39 | finder.searchPositions = SEARCH_POSITIONS; 40 | 41 | buildStructure(finder); 42 | this.finders.add(finder); 43 | }); 44 | 45 | this.size = size; 46 | } 47 | 48 | public List findInChunkPiece(PieceFinder pieceFinder) { 49 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 50 | 51 | if(!biome.getGenerationSettings().hasStructureFeature(this.getStructureFeature())) { 52 | return new ArrayList<>(); 53 | } 54 | 55 | return pieceFinder.findInChunk(); 56 | } 57 | 58 | protected abstract StructureFeature getStructureFeature(); 59 | 60 | public void addRenderers(PieceFinder pieceFinder, BlockPos origin, Color color) { 61 | this.renderers.add(new Cuboid(origin, pieceFinder.getLayout(), color)); 62 | BlockPos chunkStart = new BlockPos(origin.getX() & -16, origin.getY(), origin.getZ() & -16); 63 | this.renderers.add(new Cube(chunkStart, color)); 64 | } 65 | 66 | public Map> findInChunkPieces() { 67 | Map> result = new HashMap<>(); 68 | 69 | this.finders.forEach(pieceFinder -> { 70 | result.put(pieceFinder, this.findInChunkPiece(pieceFinder)); 71 | }); 72 | 73 | return result; 74 | } 75 | 76 | public abstract void buildStructure(PieceFinder finder); 77 | 78 | @Override 79 | public boolean isValidDimension(DimensionType dimension) { 80 | return this.isOverworld(dimension); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.BlockFinder; 8 | import kaptainwutax.seedcracker.finder.Finder; 9 | import kaptainwutax.seedcracker.render.Color; 10 | import kaptainwutax.seedcracker.render.Cube; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.block.ChestBlock; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.World; 17 | import net.minecraft.world.biome.Biome; 18 | import net.minecraft.world.dimension.DimensionType; 19 | import net.minecraft.world.gen.feature.StructureFeature; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class BuriedTreasureFinder extends BlockFinder { 25 | 26 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 27 | //Buried treasure chests always generate at (9, 9) within a chunk. 28 | int localX = pos.getX() & 15; 29 | int localZ = pos.getZ() & 15; 30 | if(localX != 9 || localZ != 9)return true; 31 | if(pos.getY() > 90)return true; 32 | return false; 33 | }); 34 | 35 | protected static final List CHEST_HOLDERS = new ArrayList<>(); 36 | 37 | static { 38 | CHEST_HOLDERS.add(Blocks.SANDSTONE.getDefaultState()); 39 | CHEST_HOLDERS.add(Blocks.STONE.getDefaultState()); 40 | CHEST_HOLDERS.add(Blocks.ANDESITE.getDefaultState()); 41 | CHEST_HOLDERS.add(Blocks.GRANITE.getDefaultState()); 42 | CHEST_HOLDERS.add(Blocks.DIORITE.getDefaultState()); 43 | 44 | //Population can turn stone, andesite, granite and diorite into ores... 45 | CHEST_HOLDERS.add(Blocks.COAL_ORE.getDefaultState()); 46 | CHEST_HOLDERS.add(Blocks.IRON_ORE.getDefaultState()); 47 | CHEST_HOLDERS.add(Blocks.GOLD_ORE.getDefaultState()); 48 | 49 | //Ocean can turn stone into gravel. 50 | CHEST_HOLDERS.add(Blocks.GRAVEL.getDefaultState()); 51 | } 52 | 53 | public BuriedTreasureFinder(World world, ChunkPos chunkPos) { 54 | super(world, chunkPos, Blocks.CHEST); 55 | this.searchPositions = SEARCH_POSITIONS; 56 | } 57 | 58 | @Override 59 | public List findInChunk() { 60 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 61 | if(!biome.getGenerationSettings().hasStructureFeature(StructureFeature.BURIED_TREASURE))return new ArrayList<>(); 62 | 63 | List result = super.findInChunk(); 64 | 65 | result.removeIf(pos -> { 66 | BlockState chest = world.getBlockState(pos); 67 | if(chest.get(ChestBlock.WATERLOGGED))return true; 68 | 69 | BlockState chestHolder = world.getBlockState(pos.down()); 70 | if(!CHEST_HOLDERS.contains(chestHolder))return true; 71 | 72 | return false; 73 | }); 74 | 75 | result.forEach(pos -> { 76 | RegionStructure.Data data = Features.BURIED_TREASURE.at(this.chunkPos.x, this.chunkPos.z); 77 | 78 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 79 | this.renderers.add(new Cube(pos, new Color(255, 255, 0))); 80 | } 81 | }); 82 | 83 | return result; 84 | } 85 | 86 | @Override 87 | public boolean isValidDimension(DimensionType dimension) { 88 | return this.isOverworld(dimension); 89 | } 90 | 91 | public static List create(World world, ChunkPos chunkPos) { 92 | List finders = new ArrayList<>(); 93 | finders.add(new BuriedTreasureFinder(world, chunkPos)); 94 | return finders; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/DesertPyramidFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.block.StairsBlock; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.util.math.ChunkPos; 14 | import net.minecraft.util.math.Direction; 15 | import net.minecraft.util.math.Vec3i; 16 | import net.minecraft.world.World; 17 | import net.minecraft.world.gen.feature.StructureFeature; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public class DesertPyramidFinder extends AbstractTempleFinder { 24 | 25 | public DesertPyramidFinder(World world, ChunkPos chunkPos) { 26 | super(world, chunkPos, new Vec3i(21, 15, 21)); 27 | } 28 | 29 | @Override 30 | public List findInChunk() { 31 | Map> result = super.findInChunkPieces(); 32 | List combinedResult = new ArrayList<>(); 33 | 34 | result.forEach((pieceFinder, positions) -> { 35 | combinedResult.addAll(positions); 36 | 37 | positions.forEach(pos -> { 38 | RegionStructure.Data data = Features.DESERT_PYRAMID.at(this.chunkPos.x, this.chunkPos.z); 39 | 40 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 41 | this.addRenderers(pieceFinder, pos, new Color(255, 0, 255)); 42 | } 43 | }); 44 | }); 45 | 46 | return combinedResult; 47 | } 48 | 49 | @Override 50 | protected StructureFeature getStructureFeature() { 51 | return StructureFeature.DESERT_PYRAMID; 52 | } 53 | 54 | @Override 55 | public void buildStructure(PieceFinder finder) { 56 | BlockState blockState_1 = Blocks.SANDSTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.NORTH); 57 | BlockState blockState_2 = Blocks.SANDSTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.SOUTH); 58 | BlockState blockState_3 = Blocks.SANDSTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.EAST); 59 | BlockState blockState_4 = Blocks.SANDSTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.WEST); 60 | finder.fillWithOutline(0, 0, 0, 4, 9, 4, Blocks.SANDSTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); 61 | finder.fillWithOutline(1, 10, 1, 3, 10, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 62 | finder.addBlock(blockState_1, 2, 10, 0); 63 | finder.addBlock(blockState_2, 2, 10, 4); 64 | finder.addBlock(blockState_3, 0, 10, 2); 65 | finder.addBlock(blockState_4, 4, 10, 2); 66 | finder.fillWithOutline(finder.width - 5, 0, 0, finder.width - 1, 9, 4, Blocks.SANDSTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); 67 | finder.fillWithOutline(finder.width - 4, 10, 1, finder.width - 2, 10, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 68 | finder.addBlock(blockState_1, finder.width - 3, 10, 0); 69 | finder.addBlock(blockState_2, finder.width - 3, 10, 4); 70 | finder.addBlock(blockState_3, finder.width - 5, 10, 2); 71 | finder.addBlock(blockState_4, finder.width - 1, 10, 2); 72 | finder.fillWithOutline(8, 0, 0, 12, 4, 4, Blocks.SANDSTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); 73 | finder.fillWithOutline(9, 1, 0, 11, 3, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 74 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 9, 1, 1); 75 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 9, 2, 1); 76 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 9, 3, 1); 77 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 10, 3, 1); 78 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 11, 3, 1); 79 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 11, 2, 1); 80 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 11, 1, 1); 81 | finder.fillWithOutline(4, 1, 1, 8, 3, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); 82 | finder.fillWithOutline(4, 1, 2, 8, 2, 2, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 83 | finder.fillWithOutline(12, 1, 1, 16, 3, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); 84 | finder.fillWithOutline(12, 1, 2, 16, 2, 2, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 85 | finder.fillWithOutline(5, 4, 5, finder.width - 6, 4, finder.depth - 6, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 86 | finder.fillWithOutline(9, 4, 9, 11, 4, 11, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 87 | finder.fillWithOutline(8, 1, 8, 8, 3, 8, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 88 | finder.fillWithOutline(12, 1, 8, 12, 3, 8, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 89 | finder.fillWithOutline(8, 1, 12, 8, 3, 12, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 90 | finder.fillWithOutline(12, 1, 12, 12, 3, 12, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 91 | finder.fillWithOutline(1, 1, 5, 4, 4, 11, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 92 | finder.fillWithOutline(finder.width - 5, 1, 5, finder.width - 2, 4, 11, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 93 | finder.fillWithOutline(6, 7, 9, 6, 7, 11, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 94 | finder.fillWithOutline(finder.width - 7, 7, 9, finder.width - 7, 7, 11, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 95 | finder.fillWithOutline(5, 5, 9, 5, 7, 11, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 96 | finder.fillWithOutline(finder.width - 6, 5, 9, finder.width - 6, 7, 11, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 97 | finder.addBlock(Blocks.AIR.getDefaultState(), 5, 5, 10); 98 | finder.addBlock(Blocks.AIR.getDefaultState(), 5, 6, 10); 99 | finder.addBlock(Blocks.AIR.getDefaultState(), 6, 6, 10); 100 | finder.addBlock(Blocks.AIR.getDefaultState(), finder.width - 6, 5, 10); 101 | finder.addBlock(Blocks.AIR.getDefaultState(), finder.width - 6, 6, 10); 102 | finder.addBlock(Blocks.AIR.getDefaultState(), finder.width - 7, 6, 10); 103 | finder.fillWithOutline(2, 4, 4, 2, 6, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 104 | finder.fillWithOutline(finder.width - 3, 4, 4, finder.width - 3, 6, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 105 | finder.addBlock(blockState_1, 2, 4, 5); 106 | finder.addBlock(blockState_1, 2, 3, 4); 107 | finder.addBlock(blockState_1, finder.width - 3, 4, 5); 108 | finder.addBlock(blockState_1, finder.width - 3, 3, 4); 109 | finder.fillWithOutline(1, 1, 3, 2, 2, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 110 | finder.fillWithOutline(finder.width - 3, 1, 3, finder.width - 2, 2, 3, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 111 | finder.addBlock(Blocks.SANDSTONE.getDefaultState(), 1, 1, 2); 112 | finder.addBlock(Blocks.SANDSTONE.getDefaultState(), finder.width - 2, 1, 2); 113 | finder.addBlock(Blocks.SANDSTONE_SLAB.getDefaultState(), 1, 2, 2); 114 | finder.addBlock(Blocks.SANDSTONE_SLAB.getDefaultState(), finder.width - 2, 2, 2); 115 | finder.addBlock(blockState_4, 2, 1, 2); 116 | finder.addBlock(blockState_3, finder.width - 3, 1, 2); 117 | finder.fillWithOutline(4, 3, 5, 4, 3, 17, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 118 | finder.fillWithOutline(finder.width - 5, 3, 5, finder.width - 5, 3, 17, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 119 | finder.fillWithOutline(3, 1, 5, 4, 2, 16, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 120 | finder.fillWithOutline(finder.width - 6, 1, 5, finder.width - 5, 2, 16, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 121 | 122 | int int_7; 123 | for(int_7 = 5; int_7 <= 17; int_7 += 2) { 124 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 4, 1, int_7); 125 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 4, 2, int_7); 126 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), finder.width - 5, 1, int_7); 127 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), finder.width - 5, 2, int_7); 128 | } 129 | 130 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 10, 0, 7); 131 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 10, 0, 8); 132 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 9, 0, 9); 133 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 11, 0, 9); 134 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 8, 0, 10); 135 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 12, 0, 10); 136 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 7, 0, 10); 137 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 13, 0, 10); 138 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 9, 0, 11); 139 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 11, 0, 11); 140 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 10, 0, 12); 141 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 10, 0, 13); 142 | finder.addBlock(Blocks.BLUE_TERRACOTTA.getDefaultState(), 10, 0, 10); 143 | 144 | for(int_7 = 0; int_7 <= finder.width - 1; int_7 += finder.width - 1) { 145 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 2, 1); 146 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 2, 2); 147 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 2, 3); 148 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 3, 1); 149 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 3, 2); 150 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 3, 3); 151 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 4, 1); 152 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), int_7, 4, 2); 153 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 4, 3); 154 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 5, 1); 155 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 5, 2); 156 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 5, 3); 157 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 6, 1); 158 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), int_7, 6, 2); 159 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 6, 3); 160 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 7, 1); 161 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 7, 2); 162 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 7, 3); 163 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 8, 1); 164 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 8, 2); 165 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 8, 3); 166 | } 167 | 168 | for(int_7 = 2; int_7 <= finder.width - 3; int_7 += finder.width - 3 - 2) { 169 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 - 1, 2, 0); 170 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 2, 0); 171 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 + 1, 2, 0); 172 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 - 1, 3, 0); 173 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 3, 0); 174 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 + 1, 3, 0); 175 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 - 1, 4, 0); 176 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), int_7, 4, 0); 177 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 + 1, 4, 0); 178 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 - 1, 5, 0); 179 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 5, 0); 180 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 + 1, 5, 0); 181 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 - 1, 6, 0); 182 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), int_7, 6, 0); 183 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 + 1, 6, 0); 184 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 - 1, 7, 0); 185 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7, 7, 0); 186 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), int_7 + 1, 7, 0); 187 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 - 1, 8, 0); 188 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7, 8, 0); 189 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), int_7 + 1, 8, 0); 190 | } 191 | 192 | finder.fillWithOutline(8, 4, 0, 12, 6, 0, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 193 | finder.addBlock(Blocks.AIR.getDefaultState(), 8, 6, 0); 194 | finder.addBlock(Blocks.AIR.getDefaultState(), 12, 6, 0); 195 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 9, 5, 0); 196 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 10, 5, 0); 197 | finder.addBlock(Blocks.ORANGE_TERRACOTTA.getDefaultState(), 11, 5, 0); 198 | finder.fillWithOutline(8, -14, 8, 12, -11, 12, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 199 | finder.fillWithOutline(8, -10, 8, 12, -10, 12, Blocks.CHISELED_SANDSTONE.getDefaultState(), Blocks.CHISELED_SANDSTONE.getDefaultState(), false); 200 | finder.fillWithOutline(8, -9, 8, 12, -9, 12, Blocks.CUT_SANDSTONE.getDefaultState(), Blocks.CUT_SANDSTONE.getDefaultState(), false); 201 | finder.fillWithOutline(8, -8, 8, 12, -1, 12, Blocks.SANDSTONE.getDefaultState(), Blocks.SANDSTONE.getDefaultState(), false); 202 | finder.fillWithOutline(9, -11, 9, 11, -1, 11, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); 203 | finder.addBlock(Blocks.STONE_PRESSURE_PLATE.getDefaultState(), 10, -11, 10); 204 | finder.fillWithOutline(9, -13, 9, 11, -13, 11, Blocks.TNT.getDefaultState(), Blocks.AIR.getDefaultState(), false); 205 | finder.addBlock(Blocks.AIR.getDefaultState(), 8, -11, 10); 206 | finder.addBlock(Blocks.AIR.getDefaultState(), 8, -10, 10); 207 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 7, -10, 10); 208 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 7, -11, 10); 209 | finder.addBlock(Blocks.AIR.getDefaultState(), 12, -11, 10); 210 | finder.addBlock(Blocks.AIR.getDefaultState(), 12, -10, 10); 211 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 13, -10, 10); 212 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 13, -11, 10); 213 | finder.addBlock(Blocks.AIR.getDefaultState(), 10, -11, 8); 214 | finder.addBlock(Blocks.AIR.getDefaultState(), 10, -10, 8); 215 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 10, -10, 7); 216 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 10, -11, 7); 217 | finder.addBlock(Blocks.AIR.getDefaultState(), 10, -11, 12); 218 | finder.addBlock(Blocks.AIR.getDefaultState(), 10, -10, 12); 219 | finder.addBlock(Blocks.CHISELED_SANDSTONE.getDefaultState(), 10, -10, 13); 220 | finder.addBlock(Blocks.CUT_SANDSTONE.getDefaultState(), 10, -11, 13); 221 | } 222 | 223 | public static List create(World world, ChunkPos chunkPos) { 224 | List finders = new ArrayList<>(); 225 | finders.add(new DesertPyramidFinder(world, chunkPos)); 226 | finders.add(new DesertPyramidFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 227 | finders.add(new DesertPyramidFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 228 | finders.add(new DesertPyramidFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 229 | return finders; 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Direction; 16 | import net.minecraft.util.math.Vec3i; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.biome.Biome; 19 | import net.minecraft.world.dimension.DimensionType; 20 | import net.minecraft.world.gen.feature.StructureFeature; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class EndCityFinder extends Finder { 28 | 29 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 30 | if(pos.getY() > 90)return true; 31 | return false; 32 | }); 33 | 34 | protected List finders = new ArrayList<>(); 35 | protected final Vec3i size = new Vec3i(8, 4, 8); 36 | 37 | public EndCityFinder(World world, ChunkPos chunkPos) { 38 | super(world, chunkPos); 39 | 40 | Direction.Type.HORIZONTAL.forEach(direction -> { 41 | PieceFinder finder = new PieceFinder(world, chunkPos, direction, size); 42 | 43 | finder.searchPositions = SEARCH_POSITIONS; 44 | 45 | buildStructure(finder); 46 | this.finders.add(finder); 47 | }); 48 | } 49 | 50 | private void buildStructure(PieceFinder finder) { 51 | BlockState air = Blocks.AIR.getDefaultState(); 52 | BlockState endstoneBricks = Blocks.END_STONE_BRICKS.getDefaultState(); 53 | BlockState purpur = Blocks.PURPUR_BLOCK.getDefaultState(); 54 | BlockState purpurPillar = Blocks.PURPUR_PILLAR.getDefaultState(); 55 | BlockState purpleGlass = Blocks.MAGENTA_STAINED_GLASS.getDefaultState(); 56 | 57 | //Walls 58 | finder.fillWithOutline(0, 0, 0, 7, 4, 7, endstoneBricks, null, false); 59 | 60 | //Wall sides 61 | finder.fillWithOutline(0, 0, 0, 0, 3, 0, purpurPillar, purpurPillar, false); 62 | finder.fillWithOutline(7, 0, 0, 7, 3, 0, purpurPillar, purpurPillar, false); 63 | finder.fillWithOutline(0, 0, 7, 0, 3, 7, purpurPillar, purpurPillar, false); 64 | finder.fillWithOutline(7, 0, 7, 7, 3, 7, purpurPillar, purpurPillar, false); 65 | 66 | //Floor 67 | finder.fillWithOutline(0, 0, 0, 7, 0, 7, purpur, purpur, false); 68 | 69 | //Doorway 70 | finder.fillWithOutline(3, 1, 0, 4, 3, 0, air, air, false); 71 | 72 | //Windows 73 | finder.fillWithOutline(0, 2, 2, 0, 3, 2, purpleGlass, purpleGlass, false); 74 | finder.fillWithOutline(0, 2, 5, 0, 3, 5, purpleGlass, purpleGlass, false); 75 | finder.fillWithOutline(7, 2, 2, 7, 3, 2, purpleGlass, purpleGlass, false); 76 | finder.fillWithOutline(7, 2, 5, 7, 3, 5, purpleGlass, purpleGlass, false); 77 | } 78 | 79 | @Override 80 | public List findInChunk() { 81 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 82 | 83 | if(!biome.getGenerationSettings().hasStructureFeature(StructureFeature.END_CITY)) { 84 | return new ArrayList<>(); 85 | } 86 | 87 | Map> result = this.findInChunkPieces(); 88 | List combinedResult = new ArrayList<>(); 89 | 90 | result.forEach((pieceFinder, positions) -> { 91 | positions.removeIf(pos -> { 92 | //Figure this out, it's not a trivial task. 93 | return false; 94 | }); 95 | 96 | combinedResult.addAll(positions); 97 | 98 | positions.forEach(pos -> { 99 | RegionStructure.Data data = Features.END_CITY.at(this.chunkPos.x, this.chunkPos.z); 100 | 101 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 102 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(153, 0, 153))); 103 | this.renderers.add(new Cube(pos, new Color(153, 0, 153))); 104 | } 105 | }); 106 | }); 107 | 108 | return combinedResult; 109 | } 110 | 111 | public Map> findInChunkPieces() { 112 | Map> result = new HashMap<>(); 113 | 114 | this.finders.forEach(pieceFinder -> { 115 | result.put(pieceFinder, pieceFinder.findInChunk()); 116 | }); 117 | 118 | return result; 119 | } 120 | 121 | @Override 122 | public boolean isValidDimension(DimensionType dimension) { 123 | return this.isEnd(dimension); 124 | } 125 | 126 | public static List create(World world, ChunkPos chunkPos) { 127 | List finders = new ArrayList<>(); 128 | finders.add(new EndCityFinder(world, chunkPos)); 129 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 130 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 131 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 132 | return finders; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Vec3i; 16 | import net.minecraft.world.World; 17 | import net.minecraft.world.gen.feature.StructureFeature; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public class IglooFinder extends AbstractTempleFinder { 24 | 25 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 26 | return false; 27 | }); 28 | 29 | public IglooFinder(World world, ChunkPos chunkPos) { 30 | super(world, chunkPos, new Vec3i(7, 5, 8)); 31 | 32 | //Igloos are weird. 33 | this.finders.forEach(finder -> { 34 | finder.searchPositions = SEARCH_POSITIONS; 35 | }); 36 | } 37 | 38 | @Override 39 | public List findInChunk() { 40 | Map> result = this.findInChunkPieces(); 41 | List combinedResult = new ArrayList<>(); 42 | 43 | result.forEach((pieceFinder, positions) -> { 44 | combinedResult.addAll(positions); 45 | 46 | positions.forEach(pos -> { 47 | RegionStructure.Data data = Features.IGLOO.at(this.chunkPos.x, this.chunkPos.z); 48 | 49 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 50 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(0, 255, 255))); 51 | this.renderers.add(new Cube(pos, new Color(0, 255, 255))); 52 | } 53 | }); 54 | }); 55 | 56 | return combinedResult; 57 | } 58 | 59 | @Override 60 | public void buildStructure(PieceFinder finder) { 61 | BlockState air = Blocks.AIR.getDefaultState(); 62 | BlockState snow = Blocks.SNOW_BLOCK.getDefaultState(); 63 | BlockState ice = Blocks.ICE.getDefaultState(); 64 | 65 | for(int y = 0; y < 3; y++) { 66 | finder.addBlock(snow, 2, y, 0); 67 | finder.addBlock(snow, 2, y, 1); 68 | finder.addBlock(snow, 1, y, 2); 69 | finder.addBlock(snow, 0, y, 3); 70 | finder.addBlock(snow, 0, y, 4); 71 | finder.addBlock(ice, 0, 1, 4); 72 | finder.addBlock(snow, 0, y, 5); 73 | finder.addBlock(snow, 1, y, 6); 74 | finder.addBlock(snow, 2, y, 7); 75 | 76 | finder.addBlock(snow, 3, y, 7); 77 | 78 | finder.addBlock(snow, 4, y, 0); 79 | finder.addBlock(snow, 4, y, 1); 80 | finder.addBlock(snow, 5, y, 2); 81 | finder.addBlock(snow, 6, y, 3); 82 | finder.addBlock(snow, 6, y, 4); 83 | finder.addBlock(ice, 6, 1, 4); 84 | finder.addBlock(snow, 6, y, 5); 85 | finder.addBlock(snow, 5, y, 6); 86 | finder.addBlock(snow, 4, y, 7); 87 | } 88 | } 89 | 90 | @Override 91 | protected StructureFeature getStructureFeature() { 92 | return StructureFeature.IGLOO; 93 | } 94 | 95 | public static List create(World world, ChunkPos chunkPos) { 96 | List finders = new ArrayList<>(); 97 | finders.add(new IglooFinder(world, chunkPos)); 98 | return finders; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/JunglePyramidFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import net.minecraft.block.*; 10 | import net.minecraft.block.enums.WallMountLocation; 11 | import net.minecraft.block.enums.WireConnection; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.util.math.ChunkPos; 14 | import net.minecraft.util.math.Direction; 15 | import net.minecraft.util.math.Vec3i; 16 | import net.minecraft.world.World; 17 | import net.minecraft.world.gen.feature.StructureFeature; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public class JunglePyramidFinder extends AbstractTempleFinder { 24 | 25 | public JunglePyramidFinder(World world, ChunkPos chunkPos) { 26 | super(world, chunkPos, new Vec3i(12, 10, 15)); 27 | } 28 | 29 | @Override 30 | public List findInChunk() { 31 | Map> result = super.findInChunkPieces(); 32 | List combinedResult = new ArrayList<>(); 33 | 34 | result.forEach((pieceFinder, positions) -> { 35 | combinedResult.addAll(positions); 36 | 37 | positions.forEach(pos -> { 38 | RegionStructure.Data data = Features.JUNGLE_PYRAMID.at(this.chunkPos.x, this.chunkPos.z); 39 | 40 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 41 | this.addRenderers(pieceFinder, pos, new Color(255, 0, 255)); 42 | } 43 | }); 44 | }); 45 | 46 | return combinedResult; 47 | } 48 | 49 | @Override 50 | protected StructureFeature getStructureFeature() { 51 | return StructureFeature.JUNGLE_PYRAMID; 52 | } 53 | 54 | @Override 55 | public void buildStructure(PieceFinder finder) { 56 | BlockState eastStairs = Blocks.COBBLESTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.EAST); 57 | BlockState westStairs = Blocks.COBBLESTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.WEST); 58 | BlockState southStairs = Blocks.COBBLESTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.SOUTH); 59 | BlockState northStairs = Blocks.COBBLESTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.NORTH); 60 | finder.addBlock(northStairs, 5, 9, 6); 61 | finder.addBlock(northStairs, 6, 9, 6); 62 | finder.addBlock(southStairs, 5, 9, 8); 63 | finder.addBlock(southStairs, 6, 9, 8); 64 | finder.addBlock(northStairs, 4, 0, 0); 65 | finder.addBlock(northStairs, 5, 0, 0); 66 | finder.addBlock(northStairs, 6, 0, 0); 67 | finder.addBlock(northStairs, 7, 0, 0); 68 | finder.addBlock(northStairs, 4, 1, 8); 69 | finder.addBlock(northStairs, 4, 2, 9); 70 | finder.addBlock(northStairs, 4, 3, 10); 71 | finder.addBlock(northStairs, 7, 1, 8); 72 | finder.addBlock(northStairs, 7, 2, 9); 73 | finder.addBlock(northStairs, 7, 3, 10); 74 | finder.addBlock(eastStairs, 4, 4, 5); 75 | finder.addBlock(westStairs, 7, 4, 5); 76 | finder.addBlock((Blocks.TRIPWIRE_HOOK.getDefaultState().with(TripwireHookBlock.FACING, Direction.EAST)).with(TripwireHookBlock.ATTACHED, true), 1, -3, 8); 77 | finder.addBlock((Blocks.TRIPWIRE_HOOK.getDefaultState().with(TripwireHookBlock.FACING, Direction.WEST)).with(TripwireHookBlock.ATTACHED, true), 4, -3, 8); 78 | finder.addBlock(((Blocks.TRIPWIRE.getDefaultState().with(TripwireBlock.EAST, true)).with(TripwireBlock.WEST, true)).with(TripwireBlock.ATTACHED, true), 2, -3, 8); 79 | finder.addBlock(((Blocks.TRIPWIRE.getDefaultState().with(TripwireBlock.EAST, true)).with(TripwireBlock.WEST, true)).with(TripwireBlock.ATTACHED, true), 3, -3, 8); 80 | BlockState blockState_5 = (Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_NORTH, WireConnection.SIDE)).with(RedstoneWireBlock.WIRE_CONNECTION_SOUTH, WireConnection.SIDE); 81 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_SOUTH, WireConnection.SIDE), 5, -3, 7); 82 | finder.addBlock(blockState_5, 5, -3, 6); 83 | finder.addBlock(blockState_5, 5, -3, 5); 84 | finder.addBlock(blockState_5, 5, -3, 4); 85 | finder.addBlock(blockState_5, 5, -3, 3); 86 | finder.addBlock(blockState_5, 5, -3, 2); 87 | finder.addBlock((Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_NORTH, WireConnection.SIDE)).with(RedstoneWireBlock.WIRE_CONNECTION_WEST, WireConnection.SIDE), 5, -3, 1); 88 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_EAST, WireConnection.SIDE), 4, -3, 1); 89 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 3, -3, 1); 90 | 91 | finder.addBlock(Blocks.VINE.getDefaultState().with(VineBlock.SOUTH, true), 3, -2, 2); 92 | finder.addBlock((Blocks.TRIPWIRE_HOOK.getDefaultState().with(TripwireHookBlock.FACING, Direction.NORTH)).with(TripwireHookBlock.ATTACHED, true), 7, -3, 1); 93 | finder.addBlock((Blocks.TRIPWIRE_HOOK.getDefaultState().with(TripwireHookBlock.FACING, Direction.SOUTH)).with(TripwireHookBlock.ATTACHED, true), 7, -3, 5); 94 | finder.addBlock(((Blocks.TRIPWIRE.getDefaultState().with(TripwireBlock.NORTH, true)).with(TripwireBlock.SOUTH, true)).with(TripwireBlock.ATTACHED, true), 7, -3, 2); 95 | finder.addBlock(((Blocks.TRIPWIRE.getDefaultState().with(TripwireBlock.NORTH, true)).with(TripwireBlock.SOUTH, true)).with(TripwireBlock.ATTACHED, true), 7, -3, 3); 96 | finder.addBlock(((Blocks.TRIPWIRE.getDefaultState().with(TripwireBlock.NORTH, true)).with(TripwireBlock.SOUTH, true)).with(TripwireBlock.ATTACHED, true), 7, -3, 4); 97 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_EAST, WireConnection.SIDE), 8, -3, 6); 98 | finder.addBlock((Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_WEST, WireConnection.SIDE)).with(RedstoneWireBlock.WIRE_CONNECTION_SOUTH, WireConnection.SIDE), 9, -3, 6); 99 | finder.addBlock((Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_NORTH, WireConnection.SIDE)).with(RedstoneWireBlock.WIRE_CONNECTION_SOUTH, WireConnection.UP), 9, -3, 5); 100 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 9, -3, 4); 101 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_NORTH, WireConnection.SIDE), 9, -2, 4); 102 | 103 | finder.addBlock(Blocks.VINE.getDefaultState().with(VineBlock.EAST, true), 8, -1, 3); 104 | finder.addBlock(Blocks.VINE.getDefaultState().with(VineBlock.EAST, true), 8, -2, 3); 105 | 106 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 9, -3, 2); 107 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 8, -3, 1); 108 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 4, -3, 5); 109 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 5, -2, 5); 110 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 5, -1, 5); 111 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 6, -3, 5); 112 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 7, -2, 5); 113 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 7, -1, 5); 114 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 8, -3, 5); 115 | finder.addBlock(Blocks.CHISELED_STONE_BRICKS.getDefaultState(), 8, -2, 11); 116 | finder.addBlock(Blocks.CHISELED_STONE_BRICKS.getDefaultState(), 9, -2, 11); 117 | finder.addBlock(Blocks.CHISELED_STONE_BRICKS.getDefaultState(), 10, -2, 11); 118 | BlockState blockState_6 = (Blocks.LEVER.getDefaultState().with(LeverBlock.FACING, Direction.NORTH)).with(LeverBlock.FACE, WallMountLocation.WALL); 119 | finder.addBlock(blockState_6, 8, -2, 12); 120 | finder.addBlock(blockState_6, 9, -2, 12); 121 | finder.addBlock(blockState_6, 10, -2, 12); 122 | finder.addBlock(Blocks.MOSSY_COBBLESTONE.getDefaultState(), 10, -2, 9); 123 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_NORTH, WireConnection.SIDE), 8, -2, 9); 124 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState().with(RedstoneWireBlock.WIRE_CONNECTION_SOUTH, WireConnection.SIDE), 8, -2, 10); 125 | finder.addBlock(Blocks.REDSTONE_WIRE.getDefaultState(), 10, -1, 9); 126 | finder.addBlock(Blocks.STICKY_PISTON.getDefaultState().with(PistonBlock.FACING, Direction.UP), 9, -2, 8); 127 | finder.addBlock(Blocks.STICKY_PISTON.getDefaultState().with(PistonBlock.FACING, Direction.WEST), 10, -2, 8); 128 | finder.addBlock(Blocks.STICKY_PISTON.getDefaultState().with(PistonBlock.FACING, Direction.WEST), 10, -1, 8); 129 | finder.addBlock(Blocks.REPEATER.getDefaultState().with(RepeaterBlock.FACING, Direction.NORTH), 10, -2, 10); 130 | } 131 | 132 | public static List create(World world, ChunkPos chunkPos) { 133 | List finders = new ArrayList<>(); 134 | finders.add(new JunglePyramidFinder(world, chunkPos)); 135 | return finders; 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Direction; 16 | import net.minecraft.util.math.Vec3i; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.biome.Biome; 19 | import net.minecraft.world.dimension.DimensionType; 20 | import net.minecraft.world.gen.feature.StructureFeature; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class MansionFinder extends Finder { 28 | 29 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 30 | if((pos.getX() & 15) != 0)return true; 31 | if((pos.getZ() & 15) != 0)return true; 32 | return false; 33 | }); 34 | 35 | protected List finders = new ArrayList<>(); 36 | protected Vec3i size = new Vec3i(16, 8, 16); 37 | 38 | public MansionFinder(World world, ChunkPos chunkPos) { 39 | super(world, chunkPos); 40 | 41 | for(Direction direction: Direction.values()) { 42 | PieceFinder finder = new PieceFinder(world, chunkPos, direction, this.size); 43 | 44 | finder.searchPositions = SEARCH_POSITIONS; 45 | 46 | buildStructure(finder); 47 | this.finders.add(finder); 48 | } 49 | } 50 | 51 | @Override 52 | public List findInChunk() { 53 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 54 | 55 | if(!biome.getGenerationSettings().hasStructureFeature(StructureFeature.MANSION)) { 56 | return new ArrayList<>(); 57 | } 58 | 59 | Map> result = this.findInChunkPieces(); 60 | List combinedResult = new ArrayList<>(); 61 | 62 | result.forEach((pieceFinder, positions) -> { 63 | combinedResult.addAll(positions); 64 | 65 | positions.forEach(pos -> { 66 | RegionStructure.Data data = Features.MANSION.at(this.chunkPos.x, this.chunkPos.z); 67 | 68 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 69 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(102, 66, 33))); 70 | this.renderers.add(new Cube(this.chunkPos.getStartPos().add(0, pos.getY(), 0), new Color(102, 66, 33))); 71 | } 72 | }); 73 | }); 74 | 75 | return combinedResult; 76 | } 77 | 78 | public Map> findInChunkPieces() { 79 | Map> result = new HashMap<>(); 80 | 81 | this.finders.forEach(pieceFinder -> { 82 | result.put(pieceFinder, pieceFinder.findInChunk()); 83 | }); 84 | 85 | return result; 86 | } 87 | 88 | public void buildStructure(PieceFinder finder) { 89 | BlockState air = Blocks.AIR.getDefaultState(); 90 | BlockState cobblestone = Blocks.COBBLESTONE.getDefaultState(); 91 | BlockState birchPlanks = Blocks.BIRCH_PLANKS.getDefaultState(); 92 | BlockState redCarpet = Blocks.RED_CARPET.getDefaultState(); 93 | BlockState whiteCarpet = Blocks.WHITE_CARPET.getDefaultState(); 94 | 95 | finder.fillWithOutline(0, 0, 0, 15, 0, 15, birchPlanks, birchPlanks, false); 96 | finder.fillWithOutline(0, 0, 8, 6, 0, 12, null, null, false); 97 | finder.fillWithOutline(0, 0, 12, 9, 0, 15, null, null, false); 98 | finder.fillWithOutline(15, 0, 0, 15, 0, 15, cobblestone, cobblestone, false); 99 | finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 15, 0, 15); 100 | finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 15, 0, 7); 101 | finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 14, 0, 7); 102 | 103 | finder.fillWithOutline(9, 1, 0, 9, 1, 8, whiteCarpet, whiteCarpet, false); 104 | finder.addBlock(whiteCarpet, 8,1, 8); 105 | finder.fillWithOutline(13, 1, 0, 13, 1, 8, whiteCarpet, whiteCarpet, false); 106 | finder.addBlock(whiteCarpet, 14,1, 8); 107 | 108 | finder.fillWithOutline(10, 1, 0, 12, 1, 15, redCarpet, redCarpet, false); 109 | } 110 | 111 | @Override 112 | public boolean isValidDimension(DimensionType dimension) { 113 | return this.isOverworld(dimension); 114 | } 115 | 116 | public static List create(World world, ChunkPos chunkPos) { 117 | List finders = new ArrayList<>(); 118 | finders.add(new MansionFinder(world, chunkPos)); 119 | return finders; 120 | } 121 | 122 | } 123 | 124 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/MonumentFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import kaptainwutax.seedcracker.render.Cube; 10 | import kaptainwutax.seedcracker.render.Cuboid; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Direction; 16 | import net.minecraft.util.math.Vec3i; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.dimension.DimensionType; 19 | 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | public class MonumentFinder extends Finder { 26 | 27 | protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 28 | if(pos.getY() != 56)return true; 29 | return false; 30 | }); 31 | 32 | protected List finders = new ArrayList<>(); 33 | protected final Vec3i size = new Vec3i(8, 5, 8); 34 | 35 | public MonumentFinder(World world, ChunkPos chunkPos) { 36 | super(world, chunkPos); 37 | 38 | PieceFinder finder = new PieceFinder(world, chunkPos, Direction.NORTH, size); 39 | 40 | finder.searchPositions = SEARCH_POSITIONS; 41 | 42 | buildStructure(finder); 43 | this.finders.add(finder); 44 | } 45 | 46 | @Override 47 | public List findInChunk() { 48 | Map> result = this.findInChunkPieces(); 49 | List combinedResult = new ArrayList<>(); 50 | 51 | result.forEach((pieceFinder, positions) -> { 52 | positions.removeIf(pos -> { 53 | //Figure this out, it's not a trivial task. 54 | return false; 55 | }); 56 | 57 | combinedResult.addAll(positions); 58 | 59 | positions.forEach(pos -> { 60 | ChunkPos monumentStart = new ChunkPos(this.chunkPos.x + 1, this.chunkPos.z + 1); 61 | RegionStructure.Data data = Features.MONUMENT.at(monumentStart.x, monumentStart.z); 62 | 63 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 64 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(0, 0, 255))); 65 | this.renderers.add(new Cube(monumentStart.getStartPos().add(0, pos.getY(), 0), new Color(0, 0, 255))); 66 | } 67 | }); 68 | }); 69 | 70 | return combinedResult; 71 | } 72 | 73 | public Map> findInChunkPieces() { 74 | Map> result = new HashMap<>(); 75 | 76 | this.finders.forEach(pieceFinder -> { 77 | result.put(pieceFinder, pieceFinder.findInChunk()); 78 | }); 79 | 80 | return result; 81 | } 82 | 83 | @Override 84 | public boolean isValidDimension(DimensionType dimension) { 85 | return this.isOverworld(dimension); 86 | } 87 | 88 | public void buildStructure(PieceFinder finder) { 89 | BlockState prismarine = Blocks.PRISMARINE.getDefaultState(); 90 | BlockState prismarineBricks = Blocks.PRISMARINE_BRICKS.getDefaultState(); 91 | BlockState darkPrismarine = Blocks.DARK_PRISMARINE.getDefaultState(); 92 | BlockState seaLantern = Blocks.SEA_LANTERN.getDefaultState(); 93 | BlockState water = Blocks.WATER.getDefaultState(); 94 | 95 | //4 bottom pillars. 96 | for(int i = 0; i < 4; i++) { 97 | int x = i >= 2 ? 7 : 0; 98 | int z = i % 2 == 0 ? 0 : 7; 99 | 100 | for(int y = 0; y < 3; y++) { 101 | finder.addBlock(prismarineBricks, x, y, z); 102 | } 103 | } 104 | 105 | //First bend. 106 | for(int i = 0; i < 4; i++) { 107 | int x = i >= 2 ? 6 : 1; 108 | int z = i % 2 == 0 ? 1 : 6; 109 | finder.addBlock(prismarineBricks, x, 3, z); 110 | } 111 | 112 | //Prismarine ring. 113 | for(int x = 2; x <= 5; x++) { 114 | for(int z = 2; z <= 5; z++) { 115 | if(x == 2 || x == 5 || z == 2 || z == 5) { 116 | finder.addBlock(prismarine, x, 4, z); 117 | } 118 | } 119 | } 120 | 121 | //Second bend. 122 | for(int i = 0; i < 4; i++) { 123 | int x = i >= 2 ? 5 : 2; 124 | int z = i % 2 == 0 ? 2 : 5; 125 | finder.addBlock(prismarineBricks, x, 4, z); 126 | finder.addBlock(seaLantern, x, 3, z); 127 | } 128 | } 129 | 130 | public static List create(World world, ChunkPos chunkPos) { 131 | List finders = new ArrayList<>(); 132 | finders.add(new MonumentFinder(world, chunkPos)); 133 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 134 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 135 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 136 | return finders; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/PieceFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.Blocks; 6 | import net.minecraft.client.MinecraftClient; 7 | import net.minecraft.util.BlockMirror; 8 | import net.minecraft.util.BlockRotation; 9 | import net.minecraft.util.math.*; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.dimension.DimensionType; 12 | 13 | import java.util.ArrayList; 14 | import java.util.LinkedHashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class PieceFinder extends Finder { 19 | 20 | protected Map structure = new LinkedHashMap<>(); 21 | private BlockBox boundingBox; 22 | protected List searchPositions = new ArrayList<>(); 23 | 24 | protected Direction facing; 25 | private BlockMirror mirror; 26 | private BlockRotation rotation; 27 | 28 | protected int width; 29 | protected int height; 30 | protected int depth; 31 | 32 | private boolean debug; 33 | 34 | public PieceFinder(World world, ChunkPos chunkPos, Direction facing, Vec3i size) { 35 | super(world, chunkPos); 36 | 37 | this.setOrientation(facing); 38 | this.width = size.getX(); 39 | this.height = size.getY(); 40 | this.depth = size.getZ(); 41 | 42 | if(this.facing.getAxis() == Direction.Axis.Z) { 43 | this.boundingBox = new BlockBox( 44 | 0, 0, 0, 45 | size.getX() - 1, size.getY() - 1, size.getZ() - 1 46 | ); 47 | } else { 48 | this.boundingBox = new BlockBox( 49 | 0, 0, 0, 50 | size.getZ() - 1, size.getY() - 1, size.getX() - 1 51 | ); 52 | } 53 | } 54 | 55 | public Vec3i getLayout() { 56 | if(this.facing.getAxis() != Direction.Axis.Z) { 57 | return new Vec3i(this.depth, this.height, this.width); 58 | } 59 | 60 | return new Vec3i(this.width, this.height, this.depth); 61 | } 62 | 63 | @Override 64 | public List findInChunk() { 65 | List result = new ArrayList<>(); 66 | 67 | if(this.structure.isEmpty()) { 68 | return result; 69 | } 70 | 71 | //FOR DEBUGGING PIECES. 72 | if(this.debug) { 73 | MinecraftClient.getInstance().execute(() -> { 74 | int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 120; 75 | 76 | if (this.chunkPos.x % 2 == 0 && this.chunkPos.z % 2 == 0) { 77 | this.structure.forEach((pos, state) -> { 78 | this.world.setBlockState(this.chunkPos.getStartPos().add(pos).add(0, y, 0), state, 0); 79 | }); 80 | } 81 | }); 82 | } 83 | 84 | for(BlockPos center: this.searchPositions) { 85 | boolean found = true; 86 | 87 | for(Map.Entry entry: this.structure.entrySet()) { 88 | BlockPos pos = this.chunkPos.getStartPos().add(center.add(entry.getKey())); 89 | BlockState state = this.world.getBlockState(pos); 90 | 91 | //Blockstate may change when it gets placed in the world, that's why it's using the block here. 92 | if(entry.getValue() != null && !state.getBlock().equals(entry.getValue().getBlock())) { 93 | found = false; 94 | break; 95 | } 96 | } 97 | 98 | if(found) { 99 | result.add(this.chunkPos.getStartPos().add(center)); 100 | } 101 | } 102 | 103 | return result; 104 | } 105 | 106 | public void setOrientation(Direction facing) { 107 | this.facing = facing; 108 | 109 | if(facing == null) { 110 | this.rotation = BlockRotation.NONE; 111 | this.mirror = BlockMirror.NONE; 112 | } else { 113 | switch(facing) { 114 | case SOUTH: 115 | this.mirror = BlockMirror.LEFT_RIGHT; 116 | this.rotation = BlockRotation.NONE; 117 | break; 118 | case WEST: 119 | this.mirror = BlockMirror.LEFT_RIGHT; 120 | this.rotation = BlockRotation.CLOCKWISE_90; 121 | break; 122 | case EAST: 123 | this.mirror = BlockMirror.NONE; 124 | this.rotation = BlockRotation.CLOCKWISE_90; 125 | break; 126 | default: 127 | this.mirror = BlockMirror.NONE; 128 | this.rotation = BlockRotation.NONE; 129 | } 130 | } 131 | 132 | } 133 | 134 | protected int applyXTransform(int x, int z) { 135 | if (this.facing == null) { 136 | return x; 137 | } else { 138 | switch(this.facing) { 139 | case NORTH: 140 | case SOUTH: 141 | return this.boundingBox.getMinX() + x; 142 | case WEST: 143 | return this.boundingBox.getMaxX() - z; 144 | case EAST: 145 | return this.boundingBox.getMinX() + z; 146 | default: 147 | return x; 148 | } 149 | } 150 | } 151 | 152 | protected int applyYTransform(int y) { 153 | return this.facing == null ? y : y + this.boundingBox.getMinY(); 154 | } 155 | 156 | protected int applyZTransform(int x, int z) { 157 | if (this.facing == null) { 158 | return z; 159 | } else { 160 | switch(this.facing) { 161 | case NORTH: 162 | return this.boundingBox.getMaxZ() - z; 163 | case SOUTH: 164 | return this.boundingBox.getMinZ() + z; 165 | case WEST: 166 | case EAST: 167 | return this.boundingBox.getMinZ() + x; 168 | default: 169 | return z; 170 | } 171 | } 172 | } 173 | 174 | protected BlockState getBlockAt(int ox, int oy, int oz) { 175 | int x = this.applyXTransform(ox, oz); 176 | int y = this.applyYTransform(oy); 177 | int z = this.applyZTransform(ox, oz); 178 | BlockPos pos = new BlockPos(x, y, z); 179 | 180 | return !this.boundingBox.contains(pos) ? 181 | Blocks.AIR.getDefaultState() : 182 | this.structure.getOrDefault(pos, Blocks.AIR.getDefaultState()); 183 | } 184 | 185 | protected void fillWithOutline(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, BlockState outline, BlockState inside, boolean onlyReplaceAir) { 186 | for(int y = minY; y <= maxY; ++y) { 187 | for(int x = minX; x <= maxX; ++x) { 188 | for(int z = minZ; z <= maxZ; ++z) { 189 | if(!onlyReplaceAir || !this.getBlockAt(x, y, z).isAir()) { 190 | if(y != minY && y != maxY && x != minX && x != maxX && z != minZ && z != maxZ) { 191 | this.addBlock(inside, x, y, z); 192 | } else { 193 | this.addBlock(outline, x, y, z); 194 | } 195 | } 196 | } 197 | } 198 | } 199 | 200 | } 201 | 202 | protected void addBlock(BlockState state, int x, int y, int z) { 203 | BlockPos pos = new BlockPos( 204 | this.applyXTransform(x, z), 205 | this.applyYTransform(y), 206 | this.applyZTransform(x, z) 207 | ); 208 | 209 | if(this.boundingBox.contains(pos)) { 210 | if(state == null) { 211 | this.structure.remove(pos); 212 | return; 213 | } 214 | 215 | if (this.mirror != BlockMirror.NONE) { 216 | state = state.mirror(this.mirror); 217 | } 218 | 219 | if (this.rotation != BlockRotation.NONE) { 220 | state = state.rotate(this.rotation); 221 | } 222 | 223 | 224 | this.structure.put(pos, state); 225 | } 226 | } 227 | 228 | @Override 229 | public boolean isValidDimension(DimensionType dimension) { 230 | return true; 231 | } 232 | 233 | public void setDebug() { 234 | this.debug = true; 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.BlockFinder; 8 | import kaptainwutax.seedcracker.finder.Finder; 9 | import kaptainwutax.seedcracker.render.Color; 10 | import kaptainwutax.seedcracker.render.Cube; 11 | import kaptainwutax.seedcracker.render.Cuboid; 12 | import net.minecraft.block.*; 13 | import net.minecraft.block.entity.BlockEntity; 14 | import net.minecraft.block.entity.ChestBlockEntity; 15 | import net.minecraft.block.enums.ChestType; 16 | import net.minecraft.tag.BlockTags; 17 | import net.minecraft.util.math.BlockBox; 18 | import net.minecraft.util.math.BlockPos; 19 | import net.minecraft.util.math.ChunkPos; 20 | import net.minecraft.util.math.Direction; 21 | import net.minecraft.world.World; 22 | import net.minecraft.world.biome.Biome; 23 | import net.minecraft.world.dimension.DimensionType; 24 | import net.minecraft.world.gen.feature.StructureFeature; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | public class ShipwreckFinder extends BlockFinder { 30 | 31 | protected static List SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> { 32 | return false; 33 | }); 34 | 35 | public ShipwreckFinder(World world, ChunkPos chunkPos) { 36 | super(world, chunkPos, Blocks.CHEST); 37 | this.searchPositions = SEARCH_POSITIONS; 38 | } 39 | 40 | @Override 41 | public List findInChunk() { 42 | Biome biome = this.world.getBiomeForNoiseGen((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2); 43 | 44 | if(!biome.getGenerationSettings().hasStructureFeature(StructureFeature.SHIPWRECK)) { 45 | return new ArrayList<>(); 46 | } 47 | 48 | List result = super.findInChunk(); 49 | 50 | result.removeIf(pos -> { 51 | BlockState state = this.world.getBlockState(pos); 52 | if(state.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE)return true; 53 | 54 | BlockEntity blockEntity = this.world.getBlockEntity(pos); 55 | if(!(blockEntity instanceof ChestBlockEntity))return true; 56 | 57 | return !this.onChestFound(pos); 58 | }); 59 | 60 | return result; 61 | } 62 | 63 | /** 64 | * Source: https://github.com/skyrising/casual-mod/blob/master/src/main/java/de/skyrising/casual/ShipwreckFinder.java 65 | * */ 66 | private boolean onChestFound(BlockPos pos) { 67 | BlockPos.Mutable mutablePos = new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ()); 68 | Direction chestFacing = world.getBlockState(pos).get(ChestBlock.FACING); 69 | 70 | int[] stairs = new int[4]; 71 | int totalStairs = 0; 72 | int[] trapdoors = new int[4]; 73 | int totalTrapdoors = 0; 74 | for(int y = -1; y <= 2; y++) { 75 | for(int x = -1; x <= 1; x++) { 76 | for(int z = -1; z <= 1; z++) { 77 | if (x == 0 && y == 0 && z == 0)continue; 78 | mutablePos.set(pos.getX() + x, pos.getY() + y, pos.getZ() + z); 79 | BlockState neighborState = world.getBlockState(mutablePos); 80 | Block neighborBlock = neighborState.getBlock(); 81 | if(neighborBlock == Blocks.VOID_AIR)return false; 82 | 83 | if(neighborBlock instanceof StairsBlock) { 84 | stairs[y + 1]++; 85 | totalStairs++; 86 | } else if(neighborBlock instanceof TrapdoorBlock) { 87 | trapdoors[y + 1]++; 88 | totalTrapdoors++; 89 | } 90 | } 91 | } 92 | } 93 | //System.out.printf("%s: chest facing %s\n", pos, chestFacing); 94 | int chestX = 4; 95 | int chestY = 2; 96 | int chestZ = 0; 97 | int length = 16; 98 | int height = 9; 99 | Direction direction = chestFacing; 100 | 101 | if(trapdoors[3] > 4) { // with_mast[_degraded] 102 | chestZ = 9; 103 | height = 21; 104 | length = 28; 105 | } else if(totalTrapdoors == 0 && stairs[3] == 3) { // upsidedown_backhalf[_degraded] 106 | if(stairs[0] == 0) { 107 | chestX = 2; 108 | chestZ = 12; 109 | direction = chestFacing.getOpposite(); 110 | } else { // redundant 111 | chestX = 3; 112 | chestY = 5; 113 | chestZ = 5; 114 | direction = chestFacing.rotateYClockwise(); 115 | } 116 | } else if(totalTrapdoors == 0) { // rightsideup that have backhalf 117 | if(stairs[0] == 4) { 118 | if(totalStairs > 4) { 119 | chestX = 6; 120 | chestY = 4; 121 | chestZ = 12; 122 | direction = chestFacing.getOpposite(); 123 | } else { // sideways backhalf 124 | chestX = 6; 125 | chestY = 3; 126 | chestZ = 8; 127 | length = 17; 128 | direction = chestFacing.getOpposite(); 129 | } 130 | } else if(stairs[0] == 3 && totalStairs > 5) { 131 | chestX = 5; 132 | chestZ = 6; 133 | direction = chestFacing.rotateYCounterclockwise(); 134 | } 135 | 136 | mutablePos.set(pos); 137 | mutablePos.move(0, -chestY, 0); 138 | mutablePos.move(direction.rotateYClockwise(), chestX - 4); 139 | mutablePos.move(direction, -chestZ - 1); 140 | 141 | if(this.world.getBlockState(mutablePos).getMaterial() == Material.WOOD) { 142 | if(length == 17) { // sideways 143 | chestZ += 11; 144 | length += 11; 145 | } else { 146 | chestZ += 12; 147 | length += 12; 148 | } 149 | mutablePos.move(0, 10, 0); 150 | 151 | BlockState b = this.world.getBlockState(mutablePos); 152 | 153 | if(this.world.getBlockState(mutablePos).isIn(BlockTags.LOGS)) { 154 | height = 21; 155 | } 156 | } 157 | } else if(totalTrapdoors == 2 && trapdoors[3] == 2 && stairs[3] == 3) { // rightsideup_fronthalf[_degraded] 158 | chestZ = 8; 159 | length = 24; 160 | } 161 | 162 | if(chestZ != 0) { 163 | mutablePos.set(pos); 164 | mutablePos.move(direction, 15 - chestZ); 165 | mutablePos.move(direction.rotateYClockwise(), chestX - 4); 166 | BlockPos.Mutable pos2 = new BlockPos.Mutable(mutablePos.getX(), mutablePos.getY(), mutablePos.getZ()); 167 | pos2.move(0, -chestY, 0); 168 | pos2.move(direction, -15); 169 | pos2.move(direction.rotateYClockwise(), 4); 170 | BlockPos.Mutable pos3 = new BlockPos.Mutable(pos2.getX(), pos2.getY(), pos2.getZ()); 171 | pos3.move(direction, length - 1); 172 | pos3.move(direction.rotateYClockwise(), -8); 173 | pos3.move(0, height - 1, 0); 174 | 175 | BlockBox box = new BlockBox( 176 | Math.min(pos2.getX(), pos3.getX()), pos2.getY(), Math.min(pos2.getZ(), pos3.getZ()), 177 | Math.max(pos2.getX(), pos3.getX()) + 1, pos3.getY() + 1, Math.max(pos2.getZ(), pos3.getZ()) + 1); 178 | 179 | mutablePos.move(-4, -chestY, -15); 180 | 181 | if((mutablePos.getX() & 0xf) == 0 && (mutablePos.getZ() & 0xf) == 0) { 182 | RegionStructure.Data data = Features.SHIPWRECK.at(new ChunkPos(mutablePos).x, new ChunkPos(mutablePos).z); 183 | 184 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 185 | this.renderers.add(new Cuboid(box, new Color(0, 255, 255))); 186 | this.renderers.add(new Cube(new ChunkPos(mutablePos).getStartPos().offset(Direction.UP, mutablePos.getY()), new Color(0, 255, 255))); 187 | return true; 188 | } 189 | } 190 | } 191 | 192 | return false; 193 | } 194 | 195 | @Override 196 | public boolean isValidDimension(DimensionType dimension) { 197 | return this.isOverworld(dimension); 198 | } 199 | 200 | public static List create(World world, ChunkPos chunkPos) { 201 | List finders = new ArrayList<>(); 202 | finders.add(new ShipwreckFinder(world, chunkPos)); 203 | 204 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 205 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 206 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 207 | 208 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 209 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); 210 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); 211 | 212 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 213 | finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1))); 214 | return finders; 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.finder.structure; 2 | 3 | import kaptainwutax.featureutils.structure.RegionStructure; 4 | import kaptainwutax.seedcracker.Features; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.finder.Finder; 8 | import kaptainwutax.seedcracker.render.Color; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.block.StairsBlock; 12 | import net.minecraft.block.enums.StairShape; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Direction; 16 | import net.minecraft.util.math.Vec3i; 17 | import net.minecraft.world.World; 18 | import net.minecraft.world.gen.feature.StructureFeature; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | public class SwampHutFinder extends AbstractTempleFinder { 25 | 26 | public SwampHutFinder(World world, ChunkPos chunkPos) { 27 | super(world, chunkPos, new Vec3i(7, 7, 9)); 28 | } 29 | 30 | @Override 31 | public List findInChunk() { 32 | Map> result = super.findInChunkPieces(); 33 | List combinedResult = new ArrayList<>(); 34 | 35 | result.forEach((pieceFinder, positions) -> { 36 | combinedResult.addAll(positions); 37 | 38 | positions.forEach(pos -> { 39 | RegionStructure.Data data = Features.SWAMP_HUT.at(this.chunkPos.x, this.chunkPos.z); 40 | 41 | if(SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 42 | this.addRenderers(pieceFinder, pos, new Color(255, 0, 255)); 43 | } 44 | }); 45 | }); 46 | 47 | return combinedResult; 48 | } 49 | 50 | @Override 51 | protected StructureFeature getStructureFeature() { 52 | return StructureFeature.SWAMP_HUT; 53 | } 54 | 55 | @Override 56 | public void buildStructure(PieceFinder finder) { 57 | finder.fillWithOutline(1, 1, 1, 5, 1, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 58 | finder.fillWithOutline(1, 4, 2, 5, 4, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 59 | finder.fillWithOutline(2, 1, 0, 4, 1, 0, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 60 | finder.fillWithOutline(2, 2, 2, 3, 3, 2, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 61 | finder.fillWithOutline(1, 2, 3, 1, 3, 6, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 62 | finder.fillWithOutline(5, 2, 3, 5, 3, 6, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 63 | finder.fillWithOutline(2, 2, 7, 4, 3, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); 64 | finder.fillWithOutline(1, 0, 2, 1, 3, 2, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); 65 | finder.fillWithOutline(5, 0, 2, 5, 3, 2, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); 66 | finder.fillWithOutline(1, 0, 7, 1, 3, 7, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); 67 | finder.fillWithOutline(5, 0, 7, 5, 3, 7, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); 68 | finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 2, 3, 2); 69 | finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 3, 3, 7); 70 | finder.addBlock(Blocks.AIR.getDefaultState(), 1, 3, 4); 71 | finder.addBlock(Blocks.AIR.getDefaultState(), 5, 3, 4); 72 | finder.addBlock(Blocks.AIR.getDefaultState(), 5, 3, 5); 73 | finder.addBlock(Blocks.POTTED_RED_MUSHROOM.getDefaultState(), 1, 3, 5); 74 | finder.addBlock(Blocks.CRAFTING_TABLE.getDefaultState(), 3, 2, 6); 75 | finder.addBlock(Blocks.CAULDRON.getDefaultState(), 4, 2, 6); 76 | finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 1, 2, 1); 77 | finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 5, 2, 1); 78 | BlockState northStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.NORTH); 79 | BlockState eastStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.EAST); 80 | BlockState westStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.WEST); 81 | BlockState southStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.SOUTH); 82 | finder.fillWithOutline(0, 4, 1, 6, 4, 1, northStairs, northStairs, false); 83 | finder.fillWithOutline(0, 4, 2, 0, 4, 7, eastStairs, eastStairs, false); 84 | finder.fillWithOutline(6, 4, 2, 6, 4, 7, westStairs, westStairs, false); 85 | finder.fillWithOutline(0, 4, 8, 6, 4, 8, southStairs, southStairs, false); 86 | finder.addBlock(northStairs.with(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), 0, 4, 1); 87 | finder.addBlock(northStairs.with(StairsBlock.SHAPE, StairShape.OUTER_LEFT), 6, 4, 1); 88 | finder.addBlock(southStairs.with(StairsBlock.SHAPE, StairShape.OUTER_LEFT), 0, 4, 8); 89 | finder.addBlock(southStairs.with(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), 6, 4, 8); 90 | } 91 | 92 | public static List create(World world, ChunkPos chunkPos) { 93 | List finders = new ArrayList<>(); 94 | finders.add(new SwampHutFinder(world, chunkPos)); 95 | return finders; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/init/ClientCommands.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.init; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.StringReader; 5 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 6 | import kaptainwutax.seedcracker.command.*; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | import net.minecraft.command.CommandException; 10 | import net.minecraft.server.command.ServerCommandSource; 11 | import net.minecraft.util.Formatting; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collection; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | public class ClientCommands { 19 | 20 | public static final String PREFIX = "seed"; 21 | public static final List COMMANDS = new ArrayList<>(); 22 | 23 | public static RenderCommand RENDER; 24 | public static FinderCommand FINDER; 25 | public static DataCommand DATA; 26 | public static CrackerCommand CRACKER; 27 | public static VersionCommand VERSION; 28 | 29 | static { 30 | COMMANDS.add(RENDER = new RenderCommand()); 31 | COMMANDS.add(FINDER = new FinderCommand()); 32 | COMMANDS.add(DATA = new DataCommand()); 33 | COMMANDS.add(CRACKER = new CrackerCommand()); 34 | COMMANDS.add(VERSION = new VersionCommand()); 35 | } 36 | 37 | public static void registerCommands(CommandDispatcher dispatcher) { 38 | COMMANDS.forEach(clientCommand -> clientCommand.register(dispatcher)); 39 | } 40 | 41 | public static boolean isClientSideCommand(String[] args) { 42 | if(args.length < 2)return false; 43 | if(!PREFIX.equals(args[0]))return false; 44 | 45 | for(ClientCommand command: COMMANDS) { 46 | if(command.getName().equals(args[1])) { 47 | return true; 48 | } 49 | } 50 | 51 | return false; 52 | } 53 | 54 | public static int executeCommand(StringReader reader) { 55 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 56 | 57 | try { 58 | return player.networkHandler.getCommandDispatcher().execute(reader, new FakeCommandSource(player)); 59 | } catch(CommandException e) { 60 | ClientCommand.sendFeedback("ur bad, git gud command", Formatting.RED, false); 61 | e.printStackTrace(); 62 | } catch(CommandSyntaxException e) { 63 | ClientCommand.sendFeedback("ur bad, git gud syntax", Formatting.RED, false); 64 | e.printStackTrace(); 65 | } catch(Exception e) { 66 | ClientCommand.sendFeedback("ur bad, wat did u do", Formatting.RED, false); 67 | e.printStackTrace(); 68 | } 69 | 70 | return 1; 71 | } 72 | 73 | /** 74 | * Magic class by Earthcomputer. 75 | * https://github.com/Earthcomputer/clientcommands/blob/fabric/src/main/java/net/earthcomputer/clientcommands/command/FakeCommandSource.java 76 | * */ 77 | public static class FakeCommandSource extends ServerCommandSource { 78 | public FakeCommandSource(ClientPlayerEntity player) { 79 | super(player, player.getPos(), player.getRotationClient(), null, 0, player.getEntityName(), player.getName(), null, player); 80 | } 81 | 82 | @Override 83 | public Collection getPlayerNames() { 84 | return MinecraftClient.getInstance().getNetworkHandler().getPlayerList() 85 | .stream().map(e -> e.getProfile().getName()).collect(Collectors.toList()); 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import com.mojang.brigadier.CommandDispatcher; 5 | import kaptainwutax.seedcracker.SeedCracker; 6 | import kaptainwutax.seedcracker.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcracker.cracker.HashedSeedData; 8 | import kaptainwutax.seedcracker.finder.FinderQueue; 9 | import kaptainwutax.seedcracker.init.ClientCommands; 10 | import kaptainwutax.seedcracker.util.Log; 11 | import net.minecraft.client.MinecraftClient; 12 | import net.minecraft.client.gui.screen.Screen; 13 | import net.minecraft.client.network.ClientPlayNetworkHandler; 14 | import net.minecraft.client.world.ClientWorld; 15 | import net.minecraft.command.CommandSource; 16 | import net.minecraft.network.ClientConnection; 17 | import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; 18 | import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket; 19 | import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; 20 | import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; 21 | import net.minecraft.server.command.ServerCommandSource; 22 | import net.minecraft.util.math.ChunkPos; 23 | import org.spongepowered.asm.mixin.Mixin; 24 | import org.spongepowered.asm.mixin.Shadow; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Inject; 27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 28 | 29 | @Mixin(ClientPlayNetworkHandler.class) 30 | public abstract class ClientPlayNetworkHandlerMixin { 31 | 32 | @Shadow private ClientWorld world; 33 | @Shadow private CommandDispatcher commandDispatcher; 34 | 35 | @Inject(method = "onChunkData", at = @At(value = "TAIL")) 36 | private void onChunkData(ChunkDataS2CPacket packet, CallbackInfo ci) { 37 | int chunkX = packet.getX(); 38 | int chunkZ = packet.getZ(); 39 | FinderQueue.get().onChunkData(this.world, new ChunkPos(chunkX, chunkZ)); 40 | } 41 | 42 | @SuppressWarnings("unchecked") 43 | @Inject(method = "", at = @At("RETURN")) 44 | public void onInit(MinecraftClient mc, Screen screen, ClientConnection connection, GameProfile profile, CallbackInfo ci) { 45 | ClientCommands.registerCommands((CommandDispatcher)(Object)this.commandDispatcher); 46 | } 47 | 48 | @SuppressWarnings("unchecked") 49 | @Inject(method = "onCommandTree", at = @At("TAIL")) 50 | public void onOnCommandTree(CommandTreeS2CPacket packet, CallbackInfo ci) { 51 | ClientCommands.registerCommands((CommandDispatcher)(Object)this.commandDispatcher); 52 | } 53 | 54 | @Inject(method = "onGameJoin", at = @At(value = "TAIL")) 55 | public void onGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) { 56 | //PRE-1.16 SUPPORTED GENERATOR TYPES 57 | //GeneratorTypeData generatorTypeData = new GeneratorTypeData(packet.getGeneratorType()); 58 | 59 | //Log.warn("Fetched the generator type [" + 60 | // I18n.translate(generatorTypeData.getGeneratorType().getStoredName()).toUpperCase() + "]."); 61 | 62 | //if(!SeedCracker.get().getDataStorage().addGeneratorTypeData(generatorTypeData)) { 63 | // Log.error("THIS GENERATOR IS NOT SUPPORTED!"); 64 | // Log.error("Overworld biome search WILL NOT run."); 65 | //} 66 | 67 | HashedSeedData hashedSeedData = new HashedSeedData(packet.getSha256Seed()); 68 | 69 | if(SeedCracker.get().getDataStorage().addHashedSeedData(hashedSeedData, DataAddedEvent.POKE_BIOMES)) { 70 | Log.warn("Fetched hashed world seed [" + hashedSeedData.getHashedSeed() + "]."); 71 | } 72 | 73 | SeedCracker.get().setActive(SeedCracker.get().isActive()); 74 | } 75 | 76 | @Inject(method = "onPlayerRespawn", at = @At(value = "TAIL")) 77 | public void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) { 78 | HashedSeedData hashedSeedData = new HashedSeedData(packet.getSha256Seed()); 79 | 80 | if(SeedCracker.get().getDataStorage().addHashedSeedData(hashedSeedData, DataAddedEvent.POKE_BIOMES)) { 81 | Log.warn("Fetched hashed world seed [" + hashedSeedData.getHashedSeed() + "]."); 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import com.mojang.brigadier.StringReader; 4 | import kaptainwutax.seedcracker.SeedCracker; 5 | import kaptainwutax.seedcracker.init.ClientCommands; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | import java.util.regex.Pattern; 13 | 14 | @Mixin(ClientPlayerEntity.class) 15 | public abstract class ClientPlayerEntityMixin { 16 | 17 | @Inject(method = "tick", at = @At("HEAD")) 18 | private void tick(CallbackInfo ci) { 19 | SeedCracker.get().getDataStorage().tick(); 20 | } 21 | 22 | @Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true) 23 | private void onSendChatMessage(String message, CallbackInfo ci) { 24 | if(message.startsWith("/")) { 25 | StringReader reader = new StringReader(message); 26 | reader.skip(); 27 | 28 | int cursor = reader.getCursor(); 29 | reader.setCursor(cursor); 30 | 31 | if(ClientCommands.isClientSideCommand(message.substring(1).split(Pattern.quote(" ")))) { 32 | ClientCommands.executeCommand(reader); 33 | ci.cancel(); 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import kaptainwutax.seedcracker.SeedCracker; 4 | import net.minecraft.client.world.ClientWorld; 5 | import net.minecraft.world.biome.Biome; 6 | import net.minecraft.world.biome.BuiltinBiomes; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | @Mixin(ClientWorld.class) 14 | public abstract class ClientWorldMixin { 15 | 16 | @Inject(method = "disconnect", at = @At("HEAD")) 17 | private void disconnect(CallbackInfo ci) { 18 | SeedCracker.get().reset(); 19 | } 20 | 21 | @Inject(method = "getGeneratorStoredBiome", at = @At("HEAD"), cancellable = true) 22 | private void getGeneratorStoredBiome(int x, int y, int z, CallbackInfoReturnable ci) { 23 | ci.setReturnValue(BuiltinBiomes.THE_VOID); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/DimensionTypeMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | import net.minecraft.util.Identifier; 5 | import net.minecraft.world.dimension.DimensionType; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | 10 | @Mixin(DimensionType.class) 11 | public class DimensionTypeMixin implements Finder.DimensionTypeCaller { 12 | 13 | @Shadow @Final private Identifier infiniburn; 14 | 15 | @Override 16 | public Identifier getInfiniburn() { 17 | return this.infiniburn; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/DummyProfilerMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import kaptainwutax.seedcracker.render.RenderQueue; 4 | import net.minecraft.util.profiler.DummyProfiler; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(DummyProfiler.class) 11 | public abstract class DummyProfilerMixin { 12 | 13 | @Inject(method = "swap(Ljava/lang/String;)V", at = @At("HEAD")) 14 | private void swap(String type, CallbackInfo ci) { 15 | RenderQueue.get().onRender(type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/GameRendererMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import kaptainwutax.seedcracker.render.RenderQueue; 4 | import net.minecraft.client.render.GameRenderer; 5 | import net.minecraft.client.util.math.MatrixStack; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(GameRenderer.class) 12 | public abstract class GameRendererMixin { 13 | 14 | @Inject(method = "renderWorld", at = @At("HEAD")) 15 | private void renderWorldStart(float delta, long time, MatrixStack matrixStack, CallbackInfo ci) { 16 | RenderQueue.get().setTrackRender(matrixStack); 17 | } 18 | 19 | @Inject(method = "renderWorld", at = @At("TAIL")) 20 | private void renderWorldFinish(float delta, long time, MatrixStack matrixStack, CallbackInfo ci) { 21 | RenderQueue.get().setTrackRender(null); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/mixin/ServerChunkManagerMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.mixin; 2 | 3 | import net.fabricmc.loader.api.FabricLoader; 4 | import net.minecraft.server.world.ServerChunkManager; 5 | import net.minecraft.server.world.ThreadedAnvilChunkStorage; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | @Mixin(ServerChunkManager.class) 14 | public class ServerChunkManagerMixin { 15 | 16 | @Shadow @Final public ThreadedAnvilChunkStorage threadedAnvilChunkStorage; 17 | 18 | @Inject(method = "getTotalChunksLoadedCount", at = @At("HEAD"), cancellable = true) 19 | public void getTotalChunksLoadedCount(CallbackInfoReturnable ci) { 20 | if(FabricLoader.getInstance().isDevelopmentEnvironment()) { 21 | int count = this.threadedAnvilChunkStorage.getTotalChunksLoadedCount(); 22 | if(count < 441)ci.setReturnValue(441); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/CustomProfile.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | public abstract class CustomProfile extends FinderProfile { 4 | 5 | public CustomProfile(String author, boolean defaultState) { 6 | super(defaultState); 7 | this.author = author; 8 | this.locked = false; 9 | } 10 | 11 | public void setAuthor(String author) { 12 | this.author = author; 13 | } 14 | 15 | public void setLocked(boolean locked) { 16 | this.locked = locked; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/FinderConfig.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Queue; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.concurrent.ConcurrentLinkedQueue; 10 | import java.util.stream.Collectors; 11 | 12 | public class FinderConfig { 13 | 14 | protected FinderProfile finderProfile = new VanillaProfile(); 15 | protected Map> activeFinders = new ConcurrentHashMap<>(); 16 | 17 | public FinderConfig() { 18 | 19 | } 20 | 21 | public List getActiveFinderTypes() { 22 | return this.finderProfile.typeStates.entrySet().stream() 23 | .filter(Map.Entry::getValue) 24 | .map(Map.Entry::getKey) 25 | .collect(Collectors.toList()); 26 | } 27 | 28 | public List getActiveFinders() { 29 | this.activeFinders.values().forEach(finders -> { 30 | finders.removeIf(Finder::isUseless); 31 | }); 32 | 33 | return this.activeFinders.values().stream() 34 | .flatMap(Queue::stream).collect(Collectors.toList()); 35 | } 36 | 37 | public void addFinder(Finder.Type type, Finder finder) { 38 | if(finder.isUseless())return; 39 | 40 | if(!this.activeFinders.containsKey(type)) { 41 | this.activeFinders.put(type, new ConcurrentLinkedQueue<>()); 42 | } 43 | 44 | this.activeFinders.get(type).add(finder); 45 | } 46 | 47 | public boolean getActive(Finder.Type type) { 48 | return this.finderProfile.typeStates.get(type); 49 | } 50 | 51 | public boolean setActive(Finder.Type type, boolean flag) { 52 | return this.finderProfile.setTypeState(type, flag); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/FinderProfile.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | 5 | import java.util.HashMap; 6 | 7 | public abstract class FinderProfile { 8 | 9 | public final HashMap typeStates = new HashMap<>(); 10 | 11 | protected String author; 12 | protected boolean locked; 13 | 14 | public FinderProfile(boolean defaultState) { 15 | for(Finder.Type type: Finder.Type.values()) { 16 | this.typeStates.put(type, defaultState); 17 | } 18 | } 19 | 20 | public String getAuthor() { 21 | return this.author; 22 | } 23 | 24 | public boolean getLocked() { 25 | return this.locked; 26 | } 27 | 28 | public boolean setTypeState(Finder.Type type, boolean state) { 29 | if(this.getLocked())return false; 30 | this.typeStates.put(type, state); 31 | return true; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/NopeProfile.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | public class NopeProfile extends FinderProfile { 4 | 5 | public NopeProfile() { 6 | super(false); 7 | this.author = "KaptainWutax"; 8 | this.locked = true; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/VanillaProfile.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | 5 | public class VanillaProfile extends FinderProfile { 6 | 7 | public VanillaProfile() { 8 | super(true); 9 | this.author = "KaptainWutax"; 10 | this.setTypeState(Finder.Type.DUNGEON, false); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/profile/YoloProfile.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.profile; 2 | 3 | import kaptainwutax.seedcracker.finder.Finder; 4 | 5 | public class YoloProfile extends CustomProfile { 6 | 7 | public YoloProfile() { 8 | super("WearBlackAllDay", false); 9 | this.setTypeState(Finder.Type.DUNGEON, true); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/Color.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | public class Color { 4 | 5 | public static final Color WHITE = new Color(255, 255, 255); 6 | 7 | private final int red; 8 | private final int green; 9 | private final int blue; 10 | 11 | public Color(int red, int green, int blue) { 12 | this.red = red; 13 | this.green = green; 14 | this.blue = blue; 15 | } 16 | 17 | public int getRed() { 18 | return this.red; 19 | } 20 | 21 | public int getGreen() { 22 | return this.green; 23 | } 24 | 25 | public int getBlue() { 26 | return this.blue; 27 | } 28 | 29 | public float getFRed() { 30 | return this.getRed() / 255.0F; 31 | } 32 | 33 | public float getFGreen() { 34 | return this.getGreen() / 255.0F; 35 | } 36 | 37 | public float getFBlue() { 38 | return this.getBlue() / 255.0F; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/Cube.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.util.math.Vec3i; 5 | 6 | public class Cube extends Cuboid { 7 | 8 | public Cube() { 9 | this(BlockPos.ORIGIN, Color.WHITE); 10 | } 11 | 12 | public Cube(BlockPos pos) { 13 | this(pos, Color.WHITE); 14 | } 15 | 16 | public Cube(BlockPos pos, Color color) { 17 | super(pos, new Vec3i(1, 1, 1), color); 18 | } 19 | 20 | @Override 21 | public BlockPos getPos() { 22 | return this.start; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/Cuboid.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | import net.minecraft.util.math.BlockBox; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.util.math.Vec3i; 6 | 7 | public class Cuboid extends Renderer { 8 | 9 | public BlockPos start; 10 | public Vec3i size; 11 | 12 | private Line[] edges = new Line[12]; 13 | 14 | public Cuboid() { 15 | this(BlockPos.ORIGIN, BlockPos.ORIGIN, Color.WHITE); 16 | } 17 | 18 | public Cuboid(BlockPos pos) { 19 | this(pos, new BlockPos(1, 1, 1), Color.WHITE); 20 | } 21 | 22 | public Cuboid(BlockPos start, BlockPos end, Color color) { 23 | this(start, new Vec3i(end.getX() - start.getX(), end.getY() - start.getY(), end.getZ() - start.getZ()), color); 24 | } 25 | 26 | public Cuboid(BlockBox box, Color color) { 27 | this(new BlockPos(box.getMinX(), box.getMinY(), box.getMinZ()), new BlockPos(box.getMaxX(), box.getMaxY(), box.getMaxZ()), color); 28 | } 29 | 30 | public Cuboid(BlockPos start, Vec3i size, Color color) { 31 | this.start = start; 32 | this.size = size; 33 | this.edges[0] = new Line(toVec3d(this.start), toVec3d(this.start.add(this.size.getX(), 0, 0)), color); 34 | this.edges[1] = new Line(toVec3d(this.start), toVec3d(this.start.add(0, this.size.getY(), 0)), color); 35 | this.edges[2] = new Line(toVec3d(this.start), toVec3d(this.start.add(0, 0, this.size.getZ())), color); 36 | this.edges[3] = new Line(toVec3d(this.start.add(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.add(this.size.getX(), 0, 0)), color); 37 | this.edges[4] = new Line(toVec3d(this.start.add(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.add(this.size.getX(), this.size.getY(), this.size.getZ())), color); 38 | this.edges[5] = new Line(toVec3d(this.start.add(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.add(0, 0, this.size.getZ())), color); 39 | this.edges[6] = new Line(toVec3d(this.start.add(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.add(this.size.getX(), 0, 0)), color); 40 | this.edges[7] = new Line(toVec3d(this.start.add(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.add(0, this.size.getY(), 0)), color); 41 | this.edges[8] = new Line(toVec3d(this.start.add(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.add(this.size.getX(), this.size.getY(), this.size.getZ())), color); 42 | this.edges[9] = new Line(toVec3d(this.start.add(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.add(0, 0, this.size.getZ())), color); 43 | this.edges[10] = new Line(toVec3d(this.start.add(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.add(0, this.size.getY(), 0)), color); 44 | this.edges[11] = new Line(toVec3d(this.start.add(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.add(this.size.getX(), this.size.getY(), this.size.getZ())), color); 45 | } 46 | 47 | @Override 48 | public void render() { 49 | if(this.start == null || this.size == null || this.edges == null)return; 50 | 51 | for(Line edge: this.edges) { 52 | if(edge == null)continue; 53 | edge.render(); 54 | } 55 | } 56 | 57 | @Override 58 | public BlockPos getPos() { 59 | return this.start.add(this.size.getX() / 2, this.size.getY() / 2, this.size.getZ() / 2); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/Line.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import net.minecraft.client.render.BufferBuilder; 5 | import net.minecraft.client.render.Tessellator; 6 | import net.minecraft.client.render.VertexFormat; 7 | import net.minecraft.client.render.VertexFormats; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.Vec3d; 10 | 11 | public class Line extends Renderer { 12 | 13 | public Vec3d start; 14 | public Vec3d end; 15 | public Color color; 16 | 17 | public Line() { 18 | this(Vec3d.ZERO, Vec3d.ZERO, Color.WHITE); 19 | } 20 | 21 | public Line(Vec3d start, Vec3d end) { 22 | this(start, end, Color.WHITE); 23 | } 24 | 25 | public Line(Vec3d start, Vec3d end, Color color) { 26 | this.start = start; 27 | this.end = end; 28 | this.color = color; 29 | } 30 | 31 | @Override 32 | public void render() { 33 | if(this.start == null || this.end == null || this.color == null)return; 34 | 35 | Vec3d camPos = this.mc.gameRenderer.getCamera().getPos(); 36 | Tessellator tessellator = Tessellator.getInstance(); 37 | BufferBuilder buffer = tessellator.getBuffer(); 38 | 39 | RenderSystem.lineWidth(3.0F); 40 | buffer.begin(VertexFormat.DrawMode.DEBUG_LINE_STRIP, VertexFormats.POSITION_COLOR); 41 | this.putVertex(buffer, camPos, this.start); 42 | this.putVertex(buffer, camPos, this.end); 43 | tessellator.draw(); 44 | } 45 | 46 | protected void putVertex(BufferBuilder buffer, Vec3d camPos, Vec3d pos) { 47 | buffer.vertex( 48 | pos.getX() - camPos.x, 49 | pos.getY() - camPos.y, 50 | pos.getZ() - camPos.z 51 | ).color( 52 | this.color.getFRed(), 53 | this.color.getFGreen(), 54 | this.color.getFBlue(), 55 | 1.0F 56 | ).next(); 57 | } 58 | 59 | @Override 60 | public BlockPos getPos() { 61 | double x = (this.end.getX() - this.start.getX()) / 2 + this.start.getX(); 62 | double y = (this.end.getY() - this.start.getY()) / 2 + this.start.getY(); 63 | double z = (this.end.getZ() - this.start.getZ()) / 2 + this.start.getZ(); 64 | return new BlockPos(x, y, z); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/RenderQueue.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | import net.minecraft.client.util.math.MatrixStack; 4 | 5 | import java.util.*; 6 | import java.util.function.Consumer; 7 | 8 | public class RenderQueue { 9 | 10 | private final static RenderQueue INSTANCE = new RenderQueue(); 11 | 12 | private Map>> typeRunnableMap = new HashMap<>(); 13 | private MatrixStack matrixStack = null; 14 | 15 | public static RenderQueue get() { 16 | return INSTANCE; 17 | } 18 | 19 | public void add(String type, Consumer runnable) { 20 | Objects.requireNonNull(type); 21 | Objects.requireNonNull(runnable); 22 | 23 | if(!this.typeRunnableMap.containsKey(type)) { 24 | this.typeRunnableMap.put(type, new ArrayList<>()); 25 | } 26 | 27 | List> runnableList = this.typeRunnableMap.get(type); 28 | runnableList.add(runnable); 29 | } 30 | 31 | public void remove(String type, Consumer runnable) { 32 | Objects.requireNonNull(type); 33 | Objects.requireNonNull(runnable); 34 | 35 | if(!this.typeRunnableMap.containsKey(type)) { 36 | return; 37 | } 38 | 39 | List> runnableList = this.typeRunnableMap.get(type); 40 | runnableList.remove(runnable); 41 | } 42 | 43 | public void setTrackRender(MatrixStack matrixStack) { 44 | this.matrixStack = matrixStack; 45 | } 46 | 47 | public void onRender(String type) { 48 | if(this.matrixStack == null || !this.typeRunnableMap.containsKey(type))return; 49 | this.typeRunnableMap.get(type).forEach(r -> r.accept(this.matrixStack)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/render/Renderer.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.render; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.util.math.Vec3d; 6 | 7 | public abstract class Renderer { 8 | 9 | protected MinecraftClient mc = MinecraftClient.getInstance(); 10 | 11 | public abstract void render(); 12 | 13 | public abstract BlockPos getPos(); 14 | 15 | protected Vec3d toVec3d(BlockPos pos) { 16 | return new Vec3d(pos.getX(), pos.getY(), pos.getZ()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/util/BiomeFixer.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.util; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.util.registry.BuiltinRegistries; 5 | import net.minecraft.util.registry.Registry; 6 | 7 | public class BiomeFixer { 8 | 9 | public static kaptainwutax.biomeutils.Biome swap(net.minecraft.world.biome.Biome biome) { 10 | return kaptainwutax.biomeutils.Biome.REGISTRY.get(MinecraftClient.getInstance().getNetworkHandler() 11 | .getRegistryManager().get(Registry.BIOME_KEY).getRawId(biome)); 12 | } 13 | 14 | public static net.minecraft.world.biome.Biome swap(kaptainwutax.biomeutils.Biome biome) { 15 | return BuiltinRegistries.BIOME.get(biome.getId()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/util/Log.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.util; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.text.*; 6 | import net.minecraft.util.Formatting; 7 | 8 | import java.util.regex.Pattern; 9 | 10 | public class Log { 11 | 12 | public static void debug(String message) { 13 | PlayerEntity player = getPlayer(); 14 | 15 | if(player != null) { 16 | schedule(() -> player.sendMessage(new LiteralText(message), false)); 17 | } 18 | } 19 | 20 | public static void warn(String message) { 21 | PlayerEntity player = getPlayer(); 22 | 23 | if(player != null) { 24 | schedule(() -> player.sendMessage(new LiteralText(message).formatted(Formatting.GREEN), false)); 25 | } 26 | } 27 | 28 | public static void error(String message) { 29 | PlayerEntity player = getPlayer(); 30 | 31 | if(player != null) { 32 | schedule(() -> player.sendMessage(new LiteralText(message).formatted(Formatting.RED), false)); 33 | } 34 | } 35 | 36 | public static void printSeed(String message, long seedValue) { 37 | String[] data = message.split(Pattern.quote("${SEED}")); 38 | String seed = String.valueOf(seedValue); 39 | Text text = Texts.bracketed((new LiteralText(seed)).styled(style -> style.withColor(Formatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, seed)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslatableText("chat.copy.click"))).withInsertion(seed))); 40 | 41 | PlayerEntity player = getPlayer(); 42 | 43 | if(player != null) { 44 | schedule(() -> player.sendMessage(new LiteralText(data[0]).append(text).append(new LiteralText(data[1])), false)); 45 | } 46 | } 47 | 48 | private static void schedule(Runnable runnable) { 49 | MinecraftClient.getInstance().execute(runnable); 50 | } 51 | 52 | private static PlayerEntity getPlayer() { 53 | return MinecraftClient.getInstance().player; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/util/PosIterator.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.util; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class PosIterator { 9 | 10 | public static Set create(BlockPos start, BlockPos end) { 11 | Set result = new HashSet<>(); 12 | 13 | for(int x = start.getX(); x <= end.getX(); x++) { 14 | for(int z = start.getZ(); z <= end.getZ(); z++) { 15 | for(int y = start.getY(); y <= end.getY(); y++) { 16 | result.add(new BlockPos(x, y, z)); 17 | } 18 | } 19 | } 20 | 21 | return result; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcracker/util/Predicates.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcracker.util; 2 | 3 | import java.util.function.BiPredicate; 4 | 5 | public class Predicates { 6 | 7 | public static BiPredicate EQUAL_TO = Integer::equals; 8 | public static BiPredicate NOT_EQUAL_TO = (a, b) -> !a.equals(b); 9 | public static BiPredicate LESS_THAN = (a, b) -> a < b; 10 | public static BiPredicate MORE_THAN = (a, b) -> a > b; 11 | public static BiPredicate LESS_OR_EQUAL_TO = (a, b) -> a <= b; 12 | public static BiPredicate MORE_OR_EQUAL_TO = (a, b) -> a >= b; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcracker/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaptainWutax/SeedCracker/9188a0f9003d3101d23bdafba15c8f4834d7fe5a/src/main/resources/assets/seedcracker/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/seedcracker/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.categories.seedcracker": "Seed Cracker", 3 | "key.open_menu": "Open Menu" 4 | } -------------------------------------------------------------------------------- /src/main/resources/assets/seedcracker/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "key.categories.seedcracker": "种子破解器", 3 | "key.open_menu": "打开菜单" 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "seedcracker", 4 | "version": "${version}", 5 | 6 | "name": "Seed Cracker", 7 | "description": "This is an example description! Tell everyone what your mod is about!", 8 | "authors": [ 9 | "KaptainWutax" 10 | ], 11 | "contact": { 12 | "homepage": "https://fabricmc.net/", 13 | "sources": "https://github.com/FabricMC/fabric-example-mod" 14 | }, 15 | 16 | "license": "CC0-1.0", 17 | "icon": "assets/seecracker/icon.png", 18 | 19 | "environment": "client", 20 | "entrypoints": { 21 | "main": [ 22 | "kaptainwutax.seedcracker.SeedCracker" 23 | ] 24 | }, 25 | "mixins": [ 26 | "seedcracker.mixins.json" 27 | ], 28 | 29 | "depends": { 30 | "fabricloader": ">=0.4.0" 31 | }, 32 | "suggests": { 33 | "flamingo": "*" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/resources/seedcracker.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "kaptainwutax.seedcracker.mixin", 5 | "compatibilityLevel": "JAVA_16", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | "ClientPlayerEntityMixin", 10 | "ClientPlayNetworkHandlerMixin", 11 | "ClientWorldMixin", 12 | "DimensionTypeMixin", 13 | "DummyProfilerMixin", 14 | "GameRendererMixin", 15 | "ServerChunkManagerMixin" 16 | ], 17 | "injectors": { 18 | "defaultRequire": 1 19 | } 20 | } 21 | --------------------------------------------------------------------------------