├── .gitignore ├── Jenkinsfile ├── LICENSE ├── README.md ├── add_jar_suffix.sh ├── bedrock.c ├── pom.xml └── src └── main └── java └── net └── daporkchop └── bedrock ├── Bedrock.java ├── Search.java ├── gui ├── BedrockFrame.java ├── BedrockOptionsDialog.java └── TriStateCheckBox.java ├── mode ├── BedrockAnyScanner.java ├── BedrockFullScanner.java ├── BedrockSubScanner.java └── SearchMode.java └── util ├── Constants.java ├── FoundCallback.java ├── Rotation.java ├── TileFilter.java └── TileScanner.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # IntelliJ files 6 | .idea/ 7 | *.iml 8 | *.ipr 9 | out/ 10 | run/ 11 | 12 | # misc. 13 | *.class 14 | *.log 15 | 16 | dependency-reduced-pom.xml 17 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | pipeline { 22 | agent any 23 | tools { 24 | git "Default" 25 | maven "Maven 3" 26 | jdk "jdk8" 27 | } 28 | options { 29 | buildDiscarder(logRotator(artifactNumToKeepStr: '5')) 30 | } 31 | stages { 32 | stage("Build") { 33 | steps { 34 | sh "mvn clean package" 35 | } 36 | post { 37 | success { 38 | sh "bash ./add_jar_suffix.sh " + sh(script: "git log -n 1 --pretty=format:'%H'", returnStdout: true).substring(0, 8) + "-" + env.BRANCH_NAME.replaceAll("[^a-zA-Z0-9.]", "_") 39 | archiveArtifacts artifacts: "target/*.jar", fingerprint: true 40 | } 41 | } 42 | } 43 | } 44 | 45 | post { 46 | always { 47 | deleteDir() 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Adapted from The MIT License (MIT) 2 | 3 | Copyright (c) 2018-$today.year DaPorkchop_ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 7 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following conditions: 9 | 10 | Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 11 | provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 14 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 15 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TerrainFinder 2 | 3 | [![Build Status](http://jenkins.daporkchop.net/job/Minecraft/job/TerrainFinder/job/master/badge/icon)](http://jenkins.daporkchop.net/job/Minecraft/job/TerrainFinder) 4 | [![Discord](https://img.shields.io/discord/428813657816956929.svg)](https://discord.gg/FrBHHCk) 5 | 6 | # IMPORTANT! READ THIS FIRST! 7 | 8 | After quite a bit of debugging, I've come to the unfortunate realization that this implementation, as well as ChromeCrusher's 9 | original code, only works for specific biomes. Any biome that doesn't use the default `generateBiomeTerrain` method, as 10 | well as any biome that uses any type of sand as a filler (beach and desert) will simply produce different results ingame. 11 | 12 | I'm going to think hard about the best way to get around this, but I have a feeling I'll end up having to re-implement the 13 | entire terrain generator in OpenCL or something. 14 | 15 | # Original README follows 16 | 17 | An optimized Java implementation of ChromeCrusher's bedrock pattern finder with a GUI. 18 | 19 | ## Building 20 | 21 | 1. [Download](https://maven.apache.org/download.cgi) and [Install](https://maven.apache.org/install.html) Maven ([Extra info for Windows](https://maven.apache.org/guides/getting-started/windows-prerequisites.html). Remember to add Maven `bin/` to your Path after extracting) 22 | 2. Clone the repository to your machine: `git clone https://github.com/DaMatrix/TerrainFinder` 23 | 3. `cd` to the clone directory 24 | 4. Run `mvn package` 25 | 5. The compiled Jar will be in the `target/` directory (choose the one that isn't prefixed with `original-`). 26 | 27 | ## Using 28 | 29 | 1. Double-click the `.jar` file or run `java -jar jarfile.jar` in your terminal. 30 | 2. The program displays a 16x16 grid representing a [chunk](https://minecraft.gamepedia.com/Chunk) in Minecraft. Click each square to set one of three states: 31 | 32 | - **Empty** (No bedrock at given location) 33 | - **Check** (There is bedrock at given location) 34 | - **Square** (Wildcard; use if unsure if there is bedrock or not) 35 | 36 | 3. Click Start. Wait for the program to find a chunk. 37 | 38 | ## Troubleshooting 39 | 40 | - Make sure you have the correct **Rotation** set in Options. 41 | - If your computer lags while using this, lower **Threads** in Options. 42 | -------------------------------------------------------------------------------- /add_jar_suffix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d target/ ]; then echo "target/ does not exist!"; exit 1; fi 4 | 5 | cd target/ 6 | rm original* 7 | for f in *.jar; do 8 | mv "$f" "`echo $f $1 | perl -pe 's/^((?:[^-]*?-)[^-]*?)((?:-sources)?\.jar) (.+)$/$1-$3$2/g' \ 9 | | perl -pe 's/^(.*?) (.+)$/$1/g'`" 10 | done 11 | -------------------------------------------------------------------------------- /bedrock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Written by ChromeCrusher for finding bases on 2b2t.org 3 | 4 | This program requires you to know a top-level bedrock pattern. 5 | A chunk-aligned 16x16 pattern (a complete chunk) is preferable and is the fastest method, but it can find any smaller pattern too (it just takes longer) 6 | You could technically search for an area larger than 16x16 (up to 48x48), but it will be slower and the chances of finding two identical 16x16 bedrock patterns is basically zero. 7 | An 8x8 pattern is usually enough to uniquely identify a location with a fairly low chance of false positives. 8 | 9 | You'll need to know which direction is north. This can be found by looking at the textures of some blocks (cobblestone for example, see http://gaming.stackexchange.com/a/23103) 10 | If you can't find which direction is north, you'll have to search for all 4 rotations of the pattern separately. I did not include a function to do it automatically because I haven't needed it. 11 | 12 | This program assumes that the chunks being searched were generated in a fairly recent version of Minecraft (probably newer than 1.7) 13 | It will not find 1.3.2 or 1.6.4 chunks, but I don't know exactly when the algorithm changed (it had to do with the structure generation limit changing from y=127 to y=255). 14 | 15 | It will work on any Minecraft world that uses normal terrain generation (with the version caveat mentioned above) 16 | It will also work regardless of the world seed, since bedrock patterns are the same in every world. 17 | 18 | This program is standalone and doesn't depend on any Java or Minecraft code. 19 | 20 | compile with: 21 | gcc bedrock.c -O3 -o bedrock 22 | run with one of the following for the demos: 23 | ./bedrock full 24 | ./bedrock sub 25 | ./bedrock any 26 | 27 | Changelog: 28 | *version 3: fixed problem with non-square search patterns 29 | 30 | To change the search pattern, edit one of the arrays below and recompile. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | // the pattern at chunk 123, -456 (real: 1968x, -7296z) 41 | int full_pattern[16*16] = {1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, 42 | 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0, 43 | 1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0, 44 | 1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0, 45 | 0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0, 46 | 0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0, 47 | 0,0,1,1,0,1,1,0,0,0,0,1,0,1,0,1, 48 | 0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0, 49 | 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 50 | 0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1, 51 | 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, 52 | 0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0, 53 | 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0, 54 | 0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1, 55 | 0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0, 56 | 0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0}; 57 | 58 | // a sub pattern of chunk -98, 76 (real: -1568x, 1216x) 59 | int sub_pattern[8*8] = {0,0,1,0,0,0,1,0, 60 | 0,0,0,0,0,0,0,0, 61 | 0,0,1,1,0,0,0,0, 62 | 0,1,1,0,0,0,0,0, 63 | 0,0,0,1,0,0,0,0, 64 | 0,0,0,0,0,1,0,1, 65 | 1,0,0,0,1,0,0,0, 66 | 0,0,1,0,0,1,0,1}; 67 | 68 | // a pattern that is part of 4 different chunks (worse case scenario) 69 | // from chunk 34, -56 (real: 544x, -896z) 70 | int any_pattern[8*8] = {0,0,0,0,0,0,0,0, 71 | 0,0,0,1,0,0,0,0, 72 | 0,1,0,0,0,0,0,0, 73 | 0,0,0,1,0,0,0,0, 74 | 0,1,1,0,0,0,0,0, 75 | 0,0,0,1,1,0,0,0, 76 | 0,0,0,0,0,0,0,0, 77 | 1,0,1,0,0,1,0,0}; 78 | 79 | // uncomment if you need to use wildcards in your chunk pattern (use 2 instead of 1) 80 | // #define WILDCARD 2 81 | 82 | // comment out to hide search times (will not pause upon match if disabled) 83 | #define DEBUG 1 84 | 85 | // global variables for returning the position of a subchunk match 86 | int sub_match_x = 0; 87 | int sub_match_z = 0; 88 | 89 | // chunk_match checks whether a 16x16 pattern matches the chunk at the given chunk coordinates 90 | // this is the fastest method to locate a chunk, it return 0 at the first mismatch, so it doesn't have to check the entire chunk 91 | // int * c: a row-major 16x16 matrix that represents the top bedrock layer pattern (top left is north-west), 0 = not bedrock, 1 = bedrock, 2 = unknown 92 | // int64_t x: chunk x coordinate (divide x coordinate by 16) 93 | // int64_t z: chunk z coordinate (divide z coordinate by 16) 94 | // returns 1 if it is a match, 0 if it is not 95 | int chunk_match(int * c, int64_t x, int64_t z) { 96 | // the java.util.Random seed used for bedrock is based on chunk coordinates, not the world seed 97 | // see world/gen/ChunkProviderOverworld.java: provideChunk from Mod Coder Pack 9.30 98 | int64_t seed = (x*341873128712LL + z*132897987541LL)^0x5DEECE66DLL; 99 | 100 | // an optimized version of the bedrock pattern generation algorithm 101 | // see world/biome/Biome.java: generateBiomeTerrain from Mod Coder Pack 9.30 102 | for(int a = 0; a < 16; ++a) { 103 | for(int b = 0; b < 16; ++b) { 104 | // this is equivalent to doing nextInt 250 times 105 | // it's the main reason this implementation is fast 106 | // I precalculated the coefficient and constant needed to advance the PRNG to the right position for generating the top-level bedrock pattern 107 | seed = seed*709490313259657689LL + 1748772144486964054LL; 108 | 109 | // get the value from the PRNG 110 | seed = seed & ((1LL << 48LL) - 1LL); 111 | 112 | // if defined, this will skip the check 113 | // use this if you have an almost complete pattern, but are missing some pieces 114 | // do not #define WILDCARD if you don't need this 115 | #ifdef WILDCARD 116 | if(c[a*16+b] != WILDCARD) 117 | #endif 118 | if(4 <= (seed >> 17) % 5) { 119 | if(c[a*16+b] != 1) 120 | // if a comparison fails, bail out 121 | return 0; 122 | } else { 123 | if(c[a*16+b] != 0) 124 | return 0; 125 | } 126 | 127 | // advances the PRNG a few more times to get ready for the next vertical column 128 | seed = seed*5985058416696778513LL + -8542997297661424380LL; 129 | } 130 | } 131 | return 1; 132 | } 133 | 134 | // sub_chunk_match: submatrix search (slower because it has to compare submatrix across entire chunk) 135 | // use this if you know the pattern is within a chunk, but don't know exactly where in the chunk 136 | // an 8x8 pattern is generally enough to uniquely identify a location, but if you already know the general area you might be able to use a smaller pattern 137 | // int * s: row-major sub-matrix 138 | // char rows: number of rows of *s 139 | // char cols: number of cols of *s 140 | // int64_t x: chunk x 141 | // int64_t z: chunk z 142 | int sub_chunk_match(int * sub, char rows, char cols, int64_t x, int64_t z) { 143 | int64_t seed = (x*341873128712LL + z*132897987541LL)^0x5DEECE66DLL; 144 | 145 | // generate and store the chunk pattern for searching 146 | int chunk[256]; 147 | 148 | for(int a = 0; a < 16; ++a) { 149 | for(int b = 0; b < 16; ++b) { 150 | seed = seed*709490313259657689LL + 1748772144486964054LL; 151 | 152 | seed = seed & ((1LL << 48LL) - 1LL); 153 | 154 | if(4 <= (seed >> 17) % 5) { 155 | chunk[a*16+b] = 1; 156 | } else { 157 | chunk[a*16+b] = 0; 158 | } 159 | 160 | seed = seed*5985058416696778513LL + -8542997297661424380LL; 161 | } 162 | } 163 | 164 | // slow search, tries every possible combination 165 | bool match; 166 | for(int m = 0; m <= 16 - rows; m++) { 167 | for(int n = 0; n <= 16 - cols; n++) { 168 | match = true; 169 | for(int i = 0; i < rows && match == true; i++) { 170 | for(int j = 0; j < cols && match == true; j++) { 171 | if(sub[i*cols+j] != chunk[(m+i)*16+(n+j)]) 172 | match = false; 173 | } 174 | } 175 | if(match) { 176 | sub_match_x = m; 177 | sub_match_z = n; 178 | 179 | return 1; 180 | } 181 | } 182 | } 183 | 184 | return 0; 185 | } 186 | 187 | // super_sub_chunk_match works like sub_chunk_match, except that it generates all the surrounding chunks and searches the 48x48 area 188 | // this is the slowest method, only use it you have no idea what the chunk boundaries are 189 | // it could use some further optimization (so it's not constantly regenerating chunks that have already been generated) 190 | // int * s: row-major sub-matrix 191 | // char rows: number of rows of *s 192 | // char cols: number of cols of *s 193 | // int64_t x: chunk x 194 | // int64_t z: chunk z 195 | int super_sub_chunk_match(int * sub, char rows, char cols, int64_t x, int64_t z) { 196 | int bchunk[48*48]; 197 | 198 | for(int64_t i = -1; i <= 1; i++) { 199 | for(int64_t j = -1; j <= 1; j++) { 200 | int64_t cx = x + j; 201 | int64_t cz = z + i; 202 | 203 | int64_t seed = (cx*341873128712LL + cz*132897987541LL)^0x5DEECE66DLL; 204 | for(int a = 0; a < 16; ++a) { 205 | for(int b = 0; b < 16; ++b) { 206 | seed = seed*709490313259657689LL + 1748772144486964054LL; 207 | seed = seed & ((1LL << 48LL) - 1LL); 208 | 209 | if(4 <= (seed >> 17) % 5) { 210 | bchunk[(16*(i+1)+a)*48+(16*(j+1)+b)] = 1; 211 | } else { 212 | bchunk[(16*(i+1)+a)*48+(16*(j+1)+b)] = 0; 213 | } 214 | 215 | seed = seed*5985058416696778513LL + -8542997297661424380LL; 216 | } 217 | } 218 | } 219 | } 220 | 221 | bool match; 222 | for(int m = 0; m <= 48 - rows; m++) { 223 | for(int n = 0; n <= 48 - cols; n++) { 224 | match = true; 225 | for(int i = 0; i < rows && match == true; i++) { 226 | for(int j = 0; j < cols && match == true; j++) { 227 | if(sub[i*cols+j] != bchunk[(m+i)*48+(n+j)]) 228 | match = false; 229 | } 230 | } 231 | if(match) { 232 | sub_match_x = m; 233 | sub_match_z = n; 234 | 235 | return 1; 236 | } 237 | } 238 | } 239 | 240 | return 0; 241 | } 242 | 243 | // prints a top-level bedrock pattern to stdout 244 | // '1' represents bedrock, '0' represents any other block 245 | // for reference, below is the 0, 0 bedrock pattern (using '*' in place of 1 and ' ' in place of 0 to make it easier to see) 246 | /* 247 | N 248 | ^ 249 | W<--->E 250 | V 251 | S 252 | 253 | ------------------ 254 | | *| 255 | | * * | 256 | |* * | 257 | |* * * | 258 | | * | 259 | | * * *| 260 | | * * *** *| 261 | | * * * | 262 | | * | 263 | |* * * * * | 264 | | * * | 265 | | * * | 266 | | * * * * * | 267 | | ** * * | 268 | | *| 269 | | *| 270 | ------------------ 271 | 272 | */ 273 | void print_chunk_pattern(int64_t x, int64_t z) { 274 | int64_t seed = (x*341873128712LL + z*132897987541LL)^0x5DEECE66DLL; 275 | 276 | for(int a = 0; a < 16; ++a) { 277 | for(int b = 0; b < 16; ++b) { 278 | seed = seed*709490313259657689LL + 1748772144486964054LL; 279 | 280 | seed = seed & ((1LL << 48LL) - 1LL); 281 | 282 | if(4 <= (seed >> 17) % 5) { 283 | printf("1,"); 284 | } else { 285 | printf("0,"); 286 | } 287 | 288 | seed = seed*5985058416696778513LL + -8542997297661424380LL; 289 | } 290 | putchar('\n'); 291 | } 292 | } 293 | 294 | // prints the chunk and all the surrounding chunks (48x48 pattern) 295 | void print_super_chunk_pattern(int64_t x, int64_t z) { 296 | int bchunk[48*48]; 297 | 298 | for(int64_t i = -1; i <= 1; i++) { 299 | for(int64_t j = -1; j <= 1; j++) { 300 | int64_t cx = x + j; 301 | int64_t cz = z + i; 302 | 303 | int64_t seed = (cx*341873128712LL + cz*132897987541LL)^0x5DEECE66DLL; 304 | for(int a = 0; a < 16; ++a) { 305 | for(int b = 0; b < 16; ++b) { 306 | seed = seed*709490313259657689LL + 1748772144486964054LL; 307 | seed = seed & ((1LL << 48LL) - 1LL); 308 | 309 | if(4 <= (seed >> 17) % 5) { 310 | bchunk[(16*(i+1)+a)*48+(16*(j+1)+b)] = 1; 311 | } else { 312 | bchunk[(16*(i+1)+a)*48+(16*(j+1)+b)] = 0; 313 | } 314 | 315 | seed = seed*5985058416696778513LL + -8542997297661424380LL; 316 | } 317 | } 318 | } 319 | } 320 | for(int i = 0; i < 48; i++) { 321 | for(int j = 0; j < 48; j++) { 322 | printf("%c,", bchunk[i*48+j] ? '1' : '0'); 323 | } 324 | printf("\n"); 325 | } 326 | } 327 | 328 | // It will search an expanding square pattern starting at the chunks 'start' distance from 0,0 and ending with the chunks 'end' distance from 0,0 329 | int bedrock_finder_fullpattern(int * pattern, int id, int step, int start, int end) { 330 | #ifdef DEBUG 331 | clock_t cs, ce; 332 | #endif 333 | for(int r = start + id; r <= end; r += step) { 334 | #ifdef DEBUG 335 | cs = clock(); 336 | #endif 337 | for(int i = -r; i <= r; i++) { 338 | if(chunk_match(pattern, i, r)) { 339 | printf("chunk: (%d, %d), real: (%d, %d)\n", i, r, i*16, r*16); 340 | #ifdef DEBUG 341 | //print_chunk_pattern(i, r); 342 | getchar(); 343 | #endif 344 | } 345 | if(chunk_match(pattern, i, -r)) { 346 | printf("chunk: (%d, %d), real: (%d, %d)\n", i, -r, i*16, (-r)*16); 347 | #ifdef DEBUG 348 | //print_chunk_pattern(i, -r); 349 | getchar(); 350 | #endif 351 | } 352 | } 353 | for(int i = -r+1; i < r; i++) { 354 | if(chunk_match(pattern, r, i)) { 355 | printf("chunk: (%d, %d), real: (%d, %d)\n", r, i, r*16, i*16); 356 | #ifdef DEBUG 357 | //print_chunk_pattern(r, i); 358 | getchar(); 359 | #endif 360 | } 361 | if(chunk_match(pattern, -r, i)) { 362 | printf("chunk: (%d, %d), real: (%d, %d)\n", -r, i, (-r)*16, i*16); 363 | #ifdef DEBUG 364 | //print_chunk_pattern(-r, i); 365 | getchar(); 366 | #endif 367 | } 368 | } 369 | #ifdef DEBUG 370 | ce = clock(); 371 | printf("%d (%f)\n", r, (double)(ce-cs)/CLOCKS_PER_SEC); 372 | #endif 373 | } 374 | return 1; 375 | } 376 | 377 | int bedrock_finder_subpattern(int * pattern, int rows, int cols, int id, int step, int start, int end) { 378 | #ifdef DEBUG 379 | clock_t cs, ce; 380 | #endif 381 | for(int r = start + id; r <= end; r += step) { 382 | #ifdef DEBUG 383 | cs = clock(); 384 | #endif 385 | for(int i = -r; i <= r; i++) { 386 | if(sub_chunk_match(pattern, rows, cols, i, r)) { 387 | printf("chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", i, r, sub_match_x, sub_match_z, i*16, r*16); 388 | #ifdef DEBUG 389 | //print_chunk_pattern(i, r); 390 | getchar(); 391 | #endif 392 | } 393 | if(sub_chunk_match(pattern, rows, cols, i, -r)) { 394 | printf("chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", i, -r, sub_match_x, sub_match_z, i*16, (-r)*16); 395 | #ifdef DEBUG 396 | //print_chunk_pattern(i, -r); 397 | getchar(); 398 | #endif 399 | } 400 | } 401 | for(int i = -r+1; i < r; i++) { 402 | if(sub_chunk_match(pattern, rows, cols, r, i)) { 403 | printf("chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", r, i, sub_match_x, sub_match_z, r*16, i*16); 404 | #ifdef DEBUG 405 | //print_chunk_pattern(r, i); 406 | getchar(); 407 | #endif 408 | } 409 | if(sub_chunk_match(pattern, rows, cols, -r, i)) { 410 | printf("chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", -r, i, sub_match_x, sub_match_z, (-r)*16, i*16); 411 | #ifdef DEBUG 412 | //print_chunk_pattern(-r, i); 413 | getchar(); 414 | #endif 415 | } 416 | } 417 | #ifdef DEBUG 418 | ce = clock(); 419 | printf("%d (%f)\n", r, (double)(ce-cs)/CLOCKS_PER_SEC); 420 | #endif 421 | } 422 | return 1; 423 | } 424 | 425 | int bedrock_finder_anypattern(int * pattern, int rows, int cols, int id, int step, int start, int end) { 426 | #ifdef DEBUG 427 | clock_t cs, ce; 428 | #endif 429 | for(int r = start + id; r <= end; r += step) { 430 | #ifdef DEBUG 431 | cs = clock(); 432 | #endif 433 | for(int i = -r; i <= r; i++) { 434 | if(super_sub_chunk_match(pattern, rows, cols, i, r)) { 435 | printf("super chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", i, r, sub_match_x, sub_match_z, i*16, r*16); 436 | #ifdef DEBUG 437 | //print_super_chunk_pattern(i, r); 438 | getchar(); 439 | #endif 440 | } 441 | if(super_sub_chunk_match(pattern, rows, cols, i, -r)) { 442 | printf("super chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", i, -r, sub_match_x, sub_match_z, i*16, (-r)*16); 443 | #ifdef DEBUG 444 | //print_super_chunk_pattern(i, -r); 445 | getchar(); 446 | #endif 447 | } 448 | } 449 | for(int i = -r+1; i < r; i++) { 450 | if(super_sub_chunk_match(pattern, rows, cols, r, i)) { 451 | printf("super chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", r, i, sub_match_x, sub_match_z, r*16, i*16); 452 | #ifdef DEBUG 453 | //print_super_chunk_pattern(r, i); 454 | getchar(); 455 | #endif 456 | } 457 | if(super_sub_chunk_match(pattern, rows, cols, -r, i)) { 458 | printf("super chunk: (%d, %d) sub-match at (%d, %d), real: (%d, %d)\n", -r, i, sub_match_x, sub_match_z, (-r)*16, i*16); 459 | #ifdef DEBUG 460 | //print_super_chunk_pattern(-r, i); 461 | getchar(); 462 | #endif 463 | } 464 | } 465 | #ifdef DEBUG 466 | ce = clock(); 467 | printf("%d (%f)\n", r, (double)(ce-cs)/CLOCKS_PER_SEC); 468 | #endif 469 | } 470 | return 1; 471 | } 472 | 473 | int main(int argc, char **argv) { 474 | 475 | // to distribute across multiple processors, decide on the number of processes, and launch the program with a process ID 476 | // for example, to run on 2 processors: 477 | // first process: ./bedrock full 0 2 478 | // second process: ./bedrock full 1 2 479 | 480 | // the optional 4th and 5th arguments define the range to search 481 | // the 4th argument is the chunk distance from spawn to start the search 482 | // the 5th argument is the chunk distance from spawn to end the search (defaults to 1875000, which is the edge of the world at 30 million) 483 | 484 | // defaults 485 | int id = 0; 486 | int step = 1; 487 | int start = 0; 488 | int end = 1875000; 489 | 490 | // help text 491 | if(argc == 1 || (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "help") == 0))) { 492 | fprintf(stderr, "usage: ./bedrock \n"); 493 | fprintf(stderr, "\nsearch type:\nfull - complete chunk search (fastest method, pattern must be complete chunk)\nsub - sub pattern search within chunk (pattern must be within a single chunk)\nany - arbitrary sub pattern search (slowest method, does not require knowledge of chunk boundaries)\n"); 494 | fprintf(stderr, "\nexample:\n./bedrock full\n"); 495 | return 1; 496 | } 497 | 498 | if(argc > 2) id = atoi(argv[2]); 499 | if(argc > 3) step = atoi(argv[3]); 500 | if(argc > 4) start = atoi(argv[4]); 501 | if(argc > 5) end = atoi(argv[5]); 502 | 503 | if(strcmp(argv[1], "full") == 0) 504 | bedrock_finder_fullpattern(full_pattern, id, step, start, end); 505 | else if(strcmp(argv[1], "sub") == 0) 506 | bedrock_finder_subpattern(sub_pattern, 8, 8, id, step, start, end); 507 | else if(strcmp(argv[1], "any") == 0) 508 | bedrock_finder_anypattern(any_pattern, 8, 8, id, step, start, end); 509 | else { 510 | fprintf(stderr, "unknown search type, use 'full', 'sub', or 'any'\n\nexample:\n./bedrock full\n"); 511 | return 1; 512 | } 513 | 514 | return 0; 515 | } 516 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 21 | 22 | 25 | 4.0.0 26 | 27 | net.daporkchop 28 | bedrock 29 | 1.0.0 30 | 31 | 32 | UTF-8 33 | 1.8 34 | 1.8 35 | 36 | 37 | 38 | 39 | DaPorkchop_ 40 | https://maven.daporkchop.net/ 41 | 42 | 43 | 44 | 45 | 46 | net.daporkchop.lib 47 | concurrent 48 | 0.5.5-SNAPSHOT 49 | 50 | 51 | org.projectlombok 52 | lombok 53 | 1.16.16 54 | provided 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-jar-plugin 69 | 70 | 71 | 72 | net.daporkchop.bedrock.Bedrock 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-shade-plugin 80 | 3.2.1 81 | 82 | 83 | 84 | 85 | package 86 | 87 | shade 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/Bedrock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock; 22 | 23 | import net.daporkchop.bedrock.gui.BedrockFrame; 24 | import net.daporkchop.bedrock.util.Constants; 25 | 26 | /** 27 | * @author DaPorkchop_ 28 | */ 29 | public class Bedrock { 30 | public static void main(String[] args) { 31 | if (false) { 32 | byte[] chunk = new byte[256]; 33 | Constants.fullChunkBedrock(chunk, -98, 76); 34 | for (int x = 0; x < 16; x++) { 35 | for (int z = 0; z < 16; z++) { 36 | System.out.print(chunk[x * 16 + z] == 0 ? ' ' : '#'); 37 | } 38 | System.out.println(); 39 | } 40 | } 41 | new BedrockFrame(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/Search.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock; 22 | 23 | import lombok.Getter; 24 | import lombok.NonNull; 25 | import lombok.RequiredArgsConstructor; 26 | import lombok.experimental.Accessors; 27 | import net.daporkchop.bedrock.util.FoundCallback; 28 | import net.daporkchop.bedrock.util.TileFilter; 29 | import net.daporkchop.bedrock.util.TileScanner; 30 | import net.daporkchop.lib.concurrent.PExecutors; 31 | import net.daporkchop.lib.concurrent.PFuture; 32 | import net.daporkchop.lib.concurrent.future.DefaultPFuture; 33 | import net.daporkchop.lib.unsafe.PUnsafe; 34 | 35 | import static net.daporkchop.bedrock.util.Constants.*; 36 | import static net.daporkchop.lib.common.util.PValidation.*; 37 | 38 | /** 39 | * Represents a search for chunk coordinates that contain something. 40 | * 41 | * @author DaPorkchop_ 42 | */ 43 | @RequiredArgsConstructor 44 | @Getter 45 | @Accessors(fluent = true) 46 | public final class Search implements Runnable { 47 | private static final long PROCESSED_OFFSET = PUnsafe.pork_getOffset(Search.class, "processed"); 48 | 49 | protected volatile long processed = 0L; 50 | 51 | protected final PFuture completedFuture = new DefaultPFuture<>(PExecutors.FORKJOINPOOL); 52 | 53 | /** 54 | * Allows rapid skipping of certain tiles. 55 | *

56 | * If {@code null}, all tiles will be checked. 57 | */ 58 | protected final TileFilter filter; 59 | 60 | /** 61 | * The actual scanner which will scan for chunks inside of a tile that match some condition. 62 | */ 63 | @NonNull 64 | protected final TileScanner scanner; 65 | 66 | /** 67 | * A function to call when a matching chunk has been found. 68 | */ 69 | @NonNull 70 | protected final FoundCallback onFound; 71 | 72 | /** 73 | * Begins searching using the given number of threads. 74 | *

75 | * Note that this can be called multiple times to add more and more workers to an ongoing task. 76 | * 77 | * @param threads the number of threads to use 78 | */ 79 | public PFuture start(int threads) { 80 | positive(threads, "threads"); 81 | for (int i = 0; i < threads; i++) { 82 | new Thread(this).start(); 83 | } 84 | return this.completedFuture; 85 | } 86 | 87 | /** 88 | * Runs a search worker. 89 | *

90 | * This will not return until the search is completed. 91 | */ 92 | @Override 93 | public void run() { 94 | try { 95 | long pos; 96 | while (!this.completedFuture.isDone() && (pos = PUnsafe.getAndAddLong(this, PROCESSED_OFFSET, 1L)) < WHOLE_WORLD_CAP) { 97 | this.doWork(pos); 98 | } 99 | ((DefaultPFuture) this.completedFuture).trySuccess(null); //complete future if whole world was scanned 100 | } catch (Exception e) { 101 | ((DefaultPFuture) this.completedFuture).tryFailure(e); 102 | throw new RuntimeException(e); 103 | } 104 | } 105 | 106 | //having this as a separate method should allow JIT to apply more aggressive optimizations 107 | private void doWork(long pos) { 108 | int tileX = extractX(pos); 109 | int tileZ = extractZ(pos); 110 | if (this.filter == null || this.filter.test(tileX, tileZ)) { 111 | long l = this.scanner.scan(tileX, tileZ); 112 | if (l != 0L) { 113 | for (int x = 0; x < TILE_SIZE; x++) { 114 | for (int z = 0; z < TILE_SIZE; z++) { 115 | if ((l & (1L << ((x << TILE_SHIFT) | z))) != 0 && !this.onFound.found((tileX << TILE_SHIFT) | x, (tileZ << TILE_SHIFT) | z)) { 116 | ((DefaultPFuture) this.completedFuture).trySuccess(null); 117 | return; 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/gui/BedrockFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.gui; 22 | 23 | import net.daporkchop.bedrock.Search; 24 | import net.daporkchop.bedrock.mode.SearchMode; 25 | import net.daporkchop.bedrock.util.Constants; 26 | import net.daporkchop.bedrock.util.Rotation; 27 | import net.daporkchop.lib.common.system.OperatingSystem; 28 | import net.daporkchop.lib.common.system.PlatformInfo; 29 | import net.daporkchop.lib.common.util.PorkUtil; 30 | 31 | import javax.swing.JButton; 32 | import javax.swing.JDialog; 33 | import javax.swing.JFrame; 34 | import javax.swing.JLabel; 35 | import javax.swing.JOptionPane; 36 | import javax.swing.JPanel; 37 | import javax.swing.UIManager; 38 | import javax.swing.UnsupportedLookAndFeelException; 39 | import java.awt.BorderLayout; 40 | import java.awt.GridLayout; 41 | import java.text.NumberFormat; 42 | import java.util.Locale; 43 | import java.util.concurrent.TimeUnit; 44 | import java.util.stream.DoubleStream; 45 | 46 | import static java.lang.Math.*; 47 | import static net.daporkchop.bedrock.util.Constants.*; 48 | 49 | public class BedrockFrame extends JFrame { 50 | public static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(Locale.US); 51 | 52 | static { 53 | try { 54 | UIManager.setLookAndFeel(PlatformInfo.OPERATING_SYSTEM == OperatingSystem.Windows ? UIManager.getSystemLookAndFeelClassName() : UIManager.getCrossPlatformLookAndFeelClassName()); 55 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 56 | ex.printStackTrace(); 57 | } 58 | } 59 | 60 | private JPanel contentPane; 61 | private JLabel scannedCount; 62 | private JButton startStopButton; 63 | private JPanel content; 64 | protected SearchMode mode; 65 | protected Rotation rotation; 66 | protected int threads = Runtime.getRuntime().availableProcessors(); 67 | private TriStateCheckBox[][] boxes; 68 | private Search search; 69 | 70 | public BedrockFrame() { 71 | this.setupUI(); 72 | this.setDefaultCloseOperation(JDialog.EXIT_ON_CLOSE); 73 | this.setContentPane(this.contentPane); 74 | this.getRootPane().setDefaultButton(this.startStopButton); 75 | 76 | this.startStopButton.addActionListener(e -> this.onClick()); 77 | this.pack(); 78 | this.setVisible(true); 79 | } 80 | 81 | private synchronized void onClick() { 82 | this.startStopButton.setEnabled(false); 83 | if (this.search == null || this.search.completedFuture().isDone()) { 84 | this.startStopButton.setText("Starting..."); 85 | System.out.println("Starting search for mode " + this.mode); 86 | int size = this.mode.size(); 87 | byte[] pattern = new byte[size * size]; 88 | for (int x = 0; x < size; x++) { 89 | for (int z = 0; z < size; z++) { 90 | int state = this.boxes[x][z].getSelectionState(); 91 | int a = state; 92 | switch (a) { 93 | case 1: 94 | state = 2; 95 | break; 96 | case 2: 97 | state = 1; 98 | break; 99 | } 100 | pattern[x * size + z] = (byte) state; 101 | } 102 | } 103 | 104 | this.search = new Search( 105 | null, 106 | this.mode.create(pattern, this.rotation), 107 | (x, z) -> { 108 | synchronized (this.search) { 109 | return JOptionPane.showOptionDialog( 110 | this, 111 | "Found match at x=" + (x << 4) + ", z=" + (z << 4) + "(chunk: x=" + x + ", z=" + z + ")", 112 | "Found match", 113 | JOptionPane.OK_CANCEL_OPTION, 114 | JOptionPane.QUESTION_MESSAGE, 115 | null, 116 | new Object[]{"Continue search", "Stop"}, 117 | null) == JOptionPane.OK_OPTION; 118 | } 119 | }); 120 | this.search.start(this.threads); 121 | 122 | new Thread(() -> { 123 | this.startStopButton.setEnabled(true); 124 | 125 | long iterations = 0L; 126 | double[] speeds = new double[150]; //15 seconds 127 | long lastTime = System.nanoTime(); 128 | long lastProcessed = 0L; 129 | 130 | while (!this.search.completedFuture().isDone()) { 131 | long now = System.nanoTime(); 132 | long processedTiles = this.search.processed(); 133 | long processedChunks = processedTiles * TILE_SIZE * TILE_SIZE; 134 | long processed = processedChunks - lastProcessed; 135 | lastProcessed = processedChunks; 136 | long timeDelta = now - lastTime; 137 | lastTime = now; 138 | System.arraycopy(speeds, 0, speeds, 1, speeds.length - 1); 139 | if (iterations++ > 10L) { 140 | speeds[0] = (double) processed * TimeUnit.SECONDS.toNanos(1L) / (double) timeDelta; 141 | } 142 | 143 | this.startStopButton.setText("Stop"); 144 | this.scannedCount.setText(String.format( 145 | "%s chunks (%s/s) - %s blocks from spawn", 146 | NUMBER_FORMAT.format(processedChunks), 147 | NUMBER_FORMAT.format(DoubleStream.of(speeds).sum() / (double) speeds.length), 148 | NUMBER_FORMAT.format(max(abs(extractX(processedTiles)), abs(extractZ(processedTiles))) << (TILE_SHIFT + 4)))); 149 | PorkUtil.sleep(100L); 150 | } 151 | 152 | this.startStopButton.setText("Start"); 153 | }, "GUI updater worker").start(); 154 | } else { 155 | this.search.completedFuture().cancel(true); 156 | this.startStopButton.setText("Start"); 157 | this.startStopButton.setEnabled(true); 158 | } 159 | } 160 | 161 | public void refreshTable() { 162 | this.content.removeAll(); 163 | this.content.setLayout(new GridLayout(this.mode.size(), this.mode.size())); 164 | this.boxes = new TriStateCheckBox[this.mode.size()][this.mode.size()]; 165 | 166 | for (int x = 0; x < this.mode.size(); x++) { 167 | for (int z = 0; z < this.mode.size(); z++) { 168 | this.content.add(this.boxes[x][z] = new TriStateCheckBox()); 169 | } 170 | } 171 | 172 | if (DEBUG) { 173 | switch (this.mode) { 174 | case FULL: { 175 | long state = seedBedrock(123, -456); 176 | for (int x = 0; x < 16; x++) { 177 | for (int z = 0; z < 16; z++) { 178 | this.boxes[x][z].setSelectionState(flagBedrock(state) << 1); 179 | state = Constants.updateBedrock(state); 180 | } 181 | } 182 | } 183 | break; 184 | case SUB: { 185 | int[] grid = {0,0,1,0,0,0,1,0, 186 | 0,0,0,0,0,0,0,0, 187 | 0,0,1,1,0,0,0,0, 188 | 0,1,1,0,0,0,0,0, 189 | 0,0,0,1,0,0,0,0, 190 | 0,0,0,0,0,1,0,1, 191 | 1,0,0,0,1,0,0,0, 192 | 0,0,1,0,0,1,0,1}; 193 | for (int x = 0, i = 0; x < 8; x++) { 194 | for (int z = 0; z < 8; z++) { 195 | this.boxes[x][z].setSelectionState(grid[i++] << 1); 196 | } 197 | } 198 | } 199 | break; 200 | case ANY: { 201 | int[] grid = {0,0,0,0,0,0,0,0, 202 | 0,0,0,1,0,0,0,0, 203 | 0,1,0,0,0,0,0,0, 204 | 0,0,0,1,0,0,0,0, 205 | 0,1,1,0,0,0,0,0, 206 | 0,0,0,1,1,0,0,0, 207 | 0,0,0,0,0,0,0,0, 208 | 1,0,1,0,0,1,0,0}; 209 | for (int x = 0, i = 0; x < 8; x++) { 210 | for (int z = 0; z < 8; z++) { 211 | this.boxes[x][z].setSelectionState(grid[i++] << 1); 212 | } 213 | } 214 | } 215 | break; 216 | } 217 | } 218 | 219 | this.revalidate(); 220 | this.repaint(); 221 | } 222 | 223 | private void setupUI() { 224 | this.contentPane = new JPanel(); 225 | this.contentPane.setLayout(new BorderLayout(0, 0)); 226 | 227 | JPanel footer = new JPanel(); 228 | footer.setLayout(new BorderLayout(0, 0)); 229 | this.contentPane.add(footer, BorderLayout.SOUTH); 230 | 231 | this.scannedCount = new JLabel(); 232 | this.scannedCount.setText("0 chunks scanned"); 233 | footer.add(this.scannedCount, BorderLayout.SOUTH); 234 | this.startStopButton = new JButton(); 235 | this.startStopButton.setText("Start"); 236 | footer.add(this.startStopButton, BorderLayout.CENTER); 237 | 238 | JButton optionsButton = new JButton(); 239 | optionsButton.setText("Options"); 240 | optionsButton.addActionListener(e -> new BedrockOptionsDialog(BedrockFrame.this)); 241 | footer.add(optionsButton, BorderLayout.WEST); 242 | 243 | JButton clearButton = new JButton(); 244 | clearButton.setText("Clear input"); 245 | clearButton.addActionListener(e -> { 246 | for (TriStateCheckBox[] col : this.boxes) { 247 | for (TriStateCheckBox box : col) { 248 | box.setSelectionState(0); 249 | } 250 | } 251 | this.revalidate(); 252 | this.repaint(); 253 | }); 254 | footer.add(clearButton, BorderLayout.EAST); 255 | 256 | this.content = new JPanel(); 257 | this.contentPane.add(this.content, BorderLayout.CENTER); 258 | 259 | this.mode = SearchMode.ANY; 260 | this.rotation = Rotation.ANY; 261 | this.refreshTable(); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/gui/BedrockOptionsDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.gui; 22 | 23 | import lombok.NonNull; 24 | import net.daporkchop.bedrock.mode.SearchMode; 25 | import net.daporkchop.bedrock.util.Rotation; 26 | 27 | import javax.swing.JComboBox; 28 | import javax.swing.JDialog; 29 | import javax.swing.JLabel; 30 | import javax.swing.JPanel; 31 | import javax.swing.JSlider; 32 | import javax.swing.SwingConstants; 33 | import javax.swing.UIManager; 34 | import javax.swing.UnsupportedLookAndFeelException; 35 | import java.awt.BorderLayout; 36 | import java.awt.GridLayout; 37 | import java.text.NumberFormat; 38 | import java.util.Arrays; 39 | import java.util.Locale; 40 | import java.util.stream.Collectors; 41 | 42 | public class BedrockOptionsDialog extends JDialog { 43 | private JPanel contentPane; 44 | private BedrockFrame dialog; 45 | 46 | public BedrockOptionsDialog(@NonNull BedrockFrame dialog) { 47 | super(dialog); 48 | this.dialog = dialog; 49 | this.setupUI(); 50 | this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 51 | this.setContentPane(this.contentPane); 52 | this.pack(); 53 | this.setVisible(true); 54 | } 55 | 56 | private void setupUI() { 57 | this.contentPane = new JPanel(); 58 | this.contentPane.setLayout(new GridLayout(3, 2)); 59 | 60 | this.contentPane.add(new JLabel("Mode")); 61 | JComboBox modeBox = new JComboBox<>(SearchMode.values()); 62 | modeBox.setSelectedItem(this.dialog.mode); 63 | modeBox.setToolTipText(Arrays.stream(SearchMode.values()) 64 | .map(mode -> String.format("%s: %s", mode.name(), mode.description())) 65 | .collect(Collectors.joining("
", "", ""))); 66 | modeBox.addItemListener(e -> { 67 | SearchMode newMode = (SearchMode) e.getItem(); 68 | if (newMode != this.dialog.mode) { 69 | this.dialog.mode = newMode; 70 | System.out.println("Changed to " + newMode); 71 | this.dialog.refreshTable(); 72 | } 73 | }); 74 | this.contentPane.add(modeBox); 75 | 76 | this.contentPane.add(new JLabel("Rotation")); 77 | JComboBox rotBox = new JComboBox<>(Rotation.values()); 78 | rotBox.setSelectedItem(this.dialog.rotation); 79 | rotBox.addItemListener(e -> { 80 | Rotation newMode = (Rotation) e.getItem(); 81 | if (newMode != this.dialog.rotation) { 82 | this.dialog.rotation = newMode; 83 | System.out.println("Changed to " + newMode); 84 | } 85 | }); 86 | this.contentPane.add(rotBox); 87 | 88 | this.contentPane.add(new JLabel("Threads")); 89 | JPanel panel = new JPanel(); 90 | panel.setLayout(new BorderLayout(0, 0)); 91 | JLabel label = new JLabel(String.valueOf(this.dialog.threads)); 92 | JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, Runtime.getRuntime().availableProcessors(), this.dialog.threads); 93 | slider.addChangeListener(e -> label.setText(String.valueOf(this.dialog.threads = slider.getValue()))); 94 | panel.add(label, BorderLayout.EAST); 95 | panel.add(slider, BorderLayout.CENTER); 96 | this.contentPane.add(panel); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/gui/TriStateCheckBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.gui; 22 | 23 | import javax.swing.*; 24 | import java.awt.*; 25 | import java.awt.event.ActionEvent; 26 | import java.awt.event.ActionListener; 27 | 28 | /** 29 | * @author s1w_ 30 | */ 31 | public class TriStateCheckBox extends JCheckBox implements Icon, ActionListener { 32 | final static boolean MIDasSELECTED = true; //consider mid-state as selected ? 33 | final static Icon icon = UIManager.getIcon("CheckBox.icon"); 34 | 35 | public TriStateCheckBox() { 36 | this(""); 37 | } 38 | 39 | public TriStateCheckBox(String text) { 40 | super(text); 41 | putClientProperty("SelectionState", 0); 42 | setIcon(this); 43 | addActionListener(this); 44 | } 45 | 46 | public TriStateCheckBox(String text, int sel) { 47 | /* 48 | tri-state checkbox has 3 selection states: 49 | * 0 unselected 50 | * 1 mid-state selection 51 | * 2 fully selected 52 | */ 53 | super(text, sel > 1); 54 | 55 | switch (sel) { 56 | case 2: 57 | setSelected(true); 58 | case 1: 59 | case 0: 60 | putClientProperty("SelectionState", sel); 61 | break; 62 | default: 63 | throw new IllegalArgumentException(); 64 | } 65 | addActionListener(this); 66 | setIcon(this); 67 | } 68 | 69 | @Override 70 | public boolean isSelected() { 71 | if (MIDasSELECTED && (getSelectionState() > 0)) return true; 72 | else return super.isSelected(); 73 | } 74 | 75 | public int getSelectionState() { 76 | return (getClientProperty("SelectionState") != null ? (int) getClientProperty("SelectionState") : 77 | super.isSelected() ? 2 : 78 | 0); 79 | } 80 | 81 | public void setSelectionState(int sel) { 82 | switch (sel) { 83 | case 2: 84 | setSelected(true); 85 | break; 86 | case 1: 87 | case 0: 88 | setSelected(false); 89 | break; 90 | default: 91 | throw new IllegalArgumentException(); 92 | } 93 | putClientProperty("SelectionState", sel); 94 | } 95 | 96 | @Override 97 | public void paintIcon(Component c, Graphics g, int x, int y) { 98 | icon.paintIcon(c, g, x, y); 99 | if (getSelectionState() != 1) return; 100 | 101 | int w = getIconWidth(); 102 | int h = getIconHeight(); 103 | g.setColor(c.isEnabled() ? new Color(51, 51, 51) : new Color(122, 138, 153)); 104 | g.fillRect(x + 4, y + 4, w - 8, h - 8); 105 | 106 | if (!c.isEnabled()) return; 107 | g.setColor(new Color(81, 81, 81)); 108 | g.drawRect(x + 4, y + 4, w - 9, h - 9); 109 | } 110 | 111 | @Override 112 | public int getIconWidth() { 113 | return icon.getIconWidth(); 114 | } 115 | 116 | @Override 117 | public int getIconHeight() { 118 | return icon.getIconHeight(); 119 | } 120 | 121 | public void actionPerformed(ActionEvent e) { 122 | TriStateCheckBox tcb = (TriStateCheckBox) e.getSource(); 123 | if (tcb.getSelectionState() == 0) 124 | tcb.setSelected(false); 125 | 126 | tcb.putClientProperty("SelectionState", tcb.getSelectionState() == 2 ? 0 : 127 | tcb.getSelectionState() + 1); 128 | 129 | // test 130 | //System.out.println(">>>>IS SELECTED: " + tcb.isSelected()); 131 | //System.out.println(">>>>IN MID STATE: " + (tcb.getSelectionState() == 1)); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/mode/BedrockAnyScanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.mode; 22 | 23 | import lombok.NonNull; 24 | import net.daporkchop.bedrock.util.Rotation; 25 | import net.daporkchop.bedrock.util.TileScanner; 26 | 27 | import static net.daporkchop.bedrock.util.Constants.*; 28 | 29 | /** 30 | * Searches for an 8x8 pattern that can overlap into neighboring chunks 31 | * 32 | * @author DaPorkchop_ 33 | */ 34 | //TODO: doesn't work 35 | @SuppressWarnings("Duplicates") 36 | public class BedrockAnyScanner implements TileScanner { 37 | private static final ThreadLocal CACHE = ThreadLocal.withInitial(() -> new byte[256 * (TILE_SIZE + 1) * (TILE_SIZE + 1)]); 38 | 39 | protected final byte[][] patterns; 40 | 41 | public BedrockAnyScanner(@NonNull byte[] pattern, @NonNull Rotation rotation) { 42 | this.patterns = rotation.bake(pattern, 8, 7, 3); 43 | } 44 | 45 | @Override 46 | public long scan(int tileX, int tileZ) { 47 | long bits = 0L; 48 | final byte[][] patterns = this.patterns; 49 | final int numPatterns = patterns.length; 50 | 51 | final byte[] cache = CACHE.get(); 52 | 53 | //generate chunk data for entire area 54 | for (int subX = 0; subX <= TILE_SIZE; subX++) { 55 | for (int subZ = 0; subZ <= TILE_SIZE; subZ++) { 56 | long state = seedBedrock((tileX << TILE_SHIFT) + subX, (tileZ << TILE_SHIFT) + subZ); 57 | for (int x = 0; x < 16; x++) { 58 | for (int z = 0; z < 16; z++) { 59 | if (4 <= (state >> 17) % 5) { 60 | cache[(subX * 16 + x) * (TILE_SIZE + 1) * 16 + subZ * 16 + z] = 1; 61 | } else { 62 | cache[(subX * 16 + x) * (TILE_SIZE + 1) * 16 + subZ * 16 + z] = 0; 63 | } 64 | state = updateBedrock(state); 65 | } 66 | } 67 | } 68 | } 69 | 70 | //do search 71 | for (int patternIndex = 0; patternIndex < numPatterns; patternIndex++) { 72 | byte[] pattern = patterns[patternIndex]; 73 | for (int subX = 0; subX <= (TILE_SIZE + 1) * 16 - 8; subX++) { 74 | for (int subZ = 0; subZ <= (TILE_SIZE + 1) * 16 - 8; subZ++) { 75 | boolean wrong = false; 76 | for (int x = 0; x < 8 && !wrong; x++) { 77 | for (int z = 0; z < 8 && !wrong; z++) { 78 | byte v = pattern[(x << 3) | z]; 79 | wrong |= (!ALLOW_WILDCARDS || v != WILDCARD) && v != cache[(subX + x) * (TILE_SIZE + 1) * 16 + (subZ + z)]; 80 | } 81 | } 82 | 83 | if (!wrong) { 84 | //if we've gotten this far, a match has been found 85 | bits |= 1L << (((subX >> 4) << TILE_SHIFT) | (subZ >> 4)); 86 | System.out.println("a"); 87 | } 88 | } 89 | } 90 | } 91 | return bits; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/mode/BedrockFullScanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.mode; 22 | 23 | import lombok.NonNull; 24 | import net.daporkchop.bedrock.util.Rotation; 25 | import net.daporkchop.bedrock.util.TileScanner; 26 | 27 | import static net.daporkchop.bedrock.util.Constants.*; 28 | 29 | /** 30 | * Scans an entire 16x16 chunk for a 16x16 pattern 31 | * 32 | * @author DaPorkchop_ 33 | */ 34 | @SuppressWarnings("Duplicates") 35 | public class BedrockFullScanner implements TileScanner { 36 | protected final byte[][] patterns; 37 | 38 | public BedrockFullScanner(@NonNull byte[] pattern, @NonNull Rotation rotation) { 39 | this.patterns = rotation.bake(pattern, 16, 0xF, 4); 40 | } 41 | 42 | @Override 43 | public long scan(int tileX, int tileZ) { 44 | long bits = 0L; 45 | final byte[][] patterns = this.patterns; 46 | final int numPatterns = patterns.length; 47 | 48 | for (int subX = 0; subX < TILE_SIZE; subX++) { 49 | for (int subZ = 0; subZ < TILE_SIZE; subZ++) { 50 | final long seed = seedBedrock((tileX << TILE_SHIFT) | subX, (tileZ << TILE_SHIFT) | subZ); 51 | PATTERN: 52 | for (int patternIndex = 0; patternIndex < numPatterns; patternIndex++) { 53 | byte[] pattern = patterns[patternIndex]; 54 | long state = seed; 55 | 56 | for (int i = 0; i < 256; i++) { 57 | byte v = pattern[i]; 58 | 59 | //~110 million/s (wildcards) 60 | //~106 million/s (wildcards, no sign extension (why?)) 61 | //~109.5 million/s (no wildcards) 62 | if (!ALLOW_WILDCARDS || v != WILDCARD) { 63 | if (4 == (state >> 17) % 5) { 64 | if (v == 0) { 65 | continue PATTERN; 66 | } 67 | } else { 68 | if (v == 1) { 69 | continue PATTERN; 70 | } 71 | } 72 | } 73 | 74 | //~107 million/s (wildcards) 75 | //~100 million/s (no wildcards) 76 | /*if ((!ALLOW_WILDCARDS || v != WILDCARD) && v != flagBedrock(state)) { 77 | continue PATTERN; 78 | }*/ 79 | 80 | state = updateBedrock(state); 81 | } 82 | 83 | bits |= 1L << ((subX << TILE_SHIFT) | subZ); 84 | break; 85 | } 86 | } 87 | } 88 | return bits; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/mode/BedrockSubScanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.mode; 22 | 23 | import lombok.NonNull; 24 | import net.daporkchop.bedrock.util.Rotation; 25 | import net.daporkchop.bedrock.util.TileScanner; 26 | 27 | import static net.daporkchop.bedrock.util.Constants.*; 28 | 29 | /** 30 | * Scans for an 8x8 pattern contained in a single chunk 31 | * 32 | * @author DaPorkchop_ 33 | */ 34 | @SuppressWarnings("Duplicates") 35 | public class BedrockSubScanner implements TileScanner { 36 | private static final ThreadLocal CHUNK_CACHE = ThreadLocal.withInitial(() -> new byte[256]); 37 | 38 | protected final byte[][] patterns; 39 | 40 | public BedrockSubScanner(@NonNull byte[] pattern, @NonNull Rotation rotation) { 41 | this.patterns = rotation.bake(pattern, 8, 7, 3); 42 | } 43 | 44 | @Override 45 | public long scan(int tileX, int tileZ) { 46 | long bits = 0L; 47 | final byte[][] patterns = this.patterns; 48 | final int numPatterns = patterns.length; 49 | 50 | final byte[] chunk = CHUNK_CACHE.get(); 51 | 52 | for (int subX = 0; subX < TILE_SIZE; subX++) { 53 | for (int subZ = 0; subZ < TILE_SIZE; subZ++) { 54 | //generate chunk data 55 | long state = seedBedrock((tileX << TILE_SHIFT) | subX, (tileZ << TILE_SHIFT) | subZ); 56 | for (int i = 0; i < 256; i++) { 57 | chunk[i] = (byte) flagBedrock(state); 58 | state = updateBedrock(state); 59 | } 60 | 61 | //do search 62 | PATTERN: 63 | for (int patternIndex = 0; patternIndex < numPatterns; patternIndex++) { 64 | byte[] pattern = patterns[patternIndex]; 65 | 66 | for (int offsetX = 0; offsetX <= 8; offsetX++) { 67 | for (int offsetZ = 0; offsetZ <= 8; offsetZ++) { 68 | boolean wrong = false; 69 | for (int x = 0; !wrong && x < 8; x++) { 70 | for (int z = 0; !wrong && z < 8; z++) { 71 | byte v = pattern[(x << 3) | z]; 72 | wrong |= (!ALLOW_WILDCARDS || v != WILDCARD) && v != chunk[((offsetX + x) << 4) | (offsetZ + z)]; 73 | } 74 | } 75 | 76 | if (!wrong) { 77 | //if we've gotten this far, a match has been found 78 | bits |= 1L << ((subX << TILE_SHIFT) | subZ); 79 | break PATTERN; 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | return bits; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/mode/SearchMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.mode; 22 | 23 | import lombok.Getter; 24 | import lombok.NonNull; 25 | import lombok.RequiredArgsConstructor; 26 | import lombok.experimental.Accessors; 27 | import net.daporkchop.bedrock.util.Rotation; 28 | import net.daporkchop.bedrock.util.TileScanner; 29 | 30 | /** 31 | * @author DaPorkchop_ 32 | */ 33 | @RequiredArgsConstructor 34 | @Getter 35 | @Accessors(fluent = true) 36 | public enum SearchMode { 37 | FULL(16, "Searches for a full, chunk-aligned 16² pattern (fastest)") { 38 | @Override 39 | public TileScanner create(@NonNull byte[] pattern, @NonNull Rotation rotation) { 40 | return new BedrockFullScanner(pattern, rotation); 41 | } 42 | }, 43 | SUB(8, "Searches for an 8x8 pattern within a single chunk (slower)") { 44 | @Override 45 | public TileScanner create(@NonNull byte[] pattern, @NonNull Rotation rotation) { 46 | return new BedrockSubScanner(pattern, rotation); 47 | } 48 | }, 49 | ANY(8, "Searches for an 8x8 pattern that may overlap chunk borders (slowest)") { 50 | @Override 51 | public TileScanner create(@NonNull byte[] pattern, @NonNull Rotation rotation) { 52 | return new BedrockAnyScanner(pattern, rotation); 53 | } 54 | }; 55 | 56 | private final int size; 57 | 58 | @NonNull 59 | private final String description; 60 | 61 | public abstract TileScanner create(@NonNull byte[] pattern, @NonNull Rotation rotation); 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/util/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.util; 22 | 23 | import lombok.NonNull; 24 | import lombok.experimental.UtilityClass; 25 | import net.daporkchop.lib.common.math.BinMath; 26 | 27 | import static java.lang.Math.*; 28 | import static net.daporkchop.lib.common.math.PMath.*; 29 | 30 | /** 31 | * @author DaPorkchop_ 32 | */ 33 | @UtilityClass 34 | public class Constants { 35 | public static final boolean ALLOW_WILDCARDS = Boolean.parseBoolean(System.getProperty("bedrock.wildcard", "true")); 36 | public static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("bedrock.debug", "false")); 37 | 38 | public static final int WILDCARD = 2; 39 | 40 | public static final int TILE_SIZE = 8; //the size of a tile in chunks 41 | public static final int TILE_SHIFT = BinMath.getNumBitsNeededFor(TILE_SIZE) - 1; 42 | 43 | public static final int WORLD_RADIUS = 30000000 >> 4 >> TILE_SHIFT; //the radius of the world in tiles 44 | public static final long WHOLE_WORLD_CAP = ((long) WORLD_RADIUS * WORLD_RADIUS) << 2L; 45 | 46 | public static int extractX(long l) { 47 | //i'll be able to understand how this works ever again, but that doesn't matter because it works now 48 | //...right? 49 | long base = floorL(sqrt(l >> 2L)); 50 | long offset = (l >> 2L) - base * base; 51 | long val = min(offset, base); 52 | return (int) (val ^ -(l & 1L)); 53 | } 54 | 55 | public static int extractZ(long l) { 56 | long base = floorL(sqrt(l >> 2L)); 57 | long offset = (l >> 2L) - base * base; 58 | long val = offset >= base + 1L ? base - offset : base; 59 | return (int) (val ^ -((l >> 1L) & 1L)); 60 | } 61 | 62 | public static long seedBedrock(int chunkX, int chunkZ) { 63 | return (((chunkX * 0x4F9939F508L + chunkZ * 0x1EF1565BD5L) ^ 0x5DEECE66DL) * 0x9D89DAE4D6C29D9L + 0x1844E300013E5B56L) & 0xFFFFFFFFFFFFL; 64 | } 65 | 66 | public static long updateBedrock(long state) { 67 | return ((state * 0x530F32EB772C5F11L + 0x89712D3873C4CD04L) * 0x9D89DAE4D6C29D9L + 0x1844E300013E5B56L) & 0xFFFFFFFFFFFFL; 68 | } 69 | 70 | public static int flagBedrock(long state) { 71 | //the state is guaranteed to fit within 48 bits, so when we shift right by 17 it'll be 31 bits and as such we can safely use 32-bit modulo on it 72 | //should theoretically be faster, i need to set up JMH and do some serious benchmarking 73 | return ((int) (state >> 17L) % 5) >> 2; 74 | } 75 | 76 | public static void fullChunkBedrock(@NonNull byte[] dst, int chunkX, int chunkZ) { 77 | long state = seedBedrock(chunkX, chunkZ); 78 | 79 | for (int i = 0; i < 256; i++) { 80 | dst[i] = (byte) (4 <= (state >> 17) % 5 ? 1 : 0); 81 | state = updateBedrock(state); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/util/FoundCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.util; 22 | 23 | /** 24 | * @author DaPorkchop_ 25 | */ 26 | public interface FoundCallback { 27 | /** 28 | * Fired whenever a matching chunk is found. 29 | * 30 | * @param chunkX the chunk's X coordinate 31 | * @param chunkZ the chunk's Z coordinate 32 | * @return whether or not the search should continue 33 | */ 34 | boolean found(int chunkX, int chunkZ); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/util/Rotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.util; 22 | 23 | import lombok.NonNull; 24 | import lombok.RequiredArgsConstructor; 25 | import net.daporkchop.lib.common.util.PArrays; 26 | 27 | /** 28 | * @author DaPorkchop_ 29 | */ 30 | @RequiredArgsConstructor 31 | public enum Rotation { 32 | NORTH(1) { 33 | @Override 34 | public void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r) { 35 | System.arraycopy(in, 0, out, 0, in.length); 36 | } 37 | }, 38 | EAST(1) { 39 | @Override 40 | public void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r) { 41 | for (int x = 0; x < size; x++) { 42 | for (int z = 0; z < size; z++) { 43 | out[(z << shift) | (x ^ mask)] = in[(x << shift) | z]; 44 | } 45 | } 46 | } 47 | }, 48 | SOUTH(1) { 49 | @Override 50 | public void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r) { 51 | for (int x = 0; x < size; x++) { 52 | for (int z = 0; z < size; z++) { 53 | out[((x ^ mask) << shift) | (z ^ mask)] = in[(x << shift) | z]; 54 | } 55 | } 56 | } 57 | }, 58 | WEST(1) { 59 | @Override 60 | public void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r) { 61 | for (int x = 0; x < size; x++) { 62 | for (int z = 0; z < size; z++) { 63 | out[((z ^ mask) << shift) | x] = in[(x << shift) | z]; 64 | } 65 | } 66 | } 67 | }, 68 | ANY(4) { 69 | @Override 70 | public void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r) { 71 | VALUES[r].rotate(in, out, size, mask, shift, 0); 72 | } 73 | }; 74 | 75 | private static final Rotation[] VALUES = values(); 76 | 77 | public final int rounds; 78 | 79 | /** 80 | * Rotates an input array and writes to an output array 81 | * 82 | * @param in the input array 83 | * @param out the output array 84 | * @param size the size (N by N) of the tile to rotate 85 | * @param mask the bitmask of the size 86 | * @param shift the number of bits to shift the X coordinate by 87 | * @param r the current round number 88 | */ 89 | public abstract void rotate(@NonNull byte[] in, @NonNull byte[] out, int size, int mask, int shift, int r); 90 | 91 | /** 92 | * Generates all permutations of the given pattern 93 | * 94 | * @param pattern the input pattern 95 | * @param size the size (N by N) of the tile to rotate 96 | * @param mask the bitmask of the size 97 | * @param shift the number of bits to shift the X coordinate by 98 | * @return all permutations of the pattern 99 | */ 100 | public byte[][] bake(@NonNull byte[] pattern, int size, int mask, int shift) { 101 | return PArrays.filled(this.rounds, byte[][]::new, i -> { 102 | byte[] arr = new byte[pattern.length]; 103 | this.rotate(pattern, arr, size, mask, shift, i); 104 | return arr; 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/util/TileFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.util; 22 | 23 | /** 24 | * Filters tiles so that only certain ones will be tested. 25 | * 26 | * @author DaPorkchop_ 27 | */ 28 | public interface TileFilter { 29 | boolean test(int tileX, int tileZ); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/daporkchop/bedrock/util/TileScanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018-2020 DaPorkchop_ 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 9 | * is furnished to do so, subject to the following conditions: 10 | * 11 | * Any persons and/or organizations using this software must include the above copyright notice and this permission notice, 12 | * provide sufficient credit to the original authors of the project (IE: DaPorkchop_), as well as provide a link to the original project. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | package net.daporkchop.bedrock.util; 22 | 23 | /** 24 | * Scans tiles for certain features. 25 | * 26 | * @author DaPorkchop_ 27 | */ 28 | public interface TileScanner { 29 | /** 30 | * Scans the given tile. 31 | * 32 | * @param tileX the tile's X coordinate 33 | * @param tileZ the tile's Z coordinate 34 | * @return a bitmask of all chunks that were found in the tile in XZ order 35 | */ 36 | long scan(int tileX, int tileZ); 37 | } 38 | --------------------------------------------------------------------------------