├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── backup ├── CMakeLists.txt ├── README.md ├── cubiomes │ ├── .gitattributes │ ├── .gitignore │ ├── LICENSE │ ├── LayerSummary.pdf │ ├── Makefile │ ├── README.md │ ├── docs │ │ ├── LayerSummary.tex │ │ ├── layers.odg │ │ └── layers.pdf │ ├── generator.c │ ├── generator.h │ ├── javarnd.h │ ├── layers.c │ ├── layers.h │ ├── mcrandom.c │ ├── mcrandom.h │ ├── tests.c │ ├── util.c │ └── util.h ├── finder.cpp ├── finder.h ├── main.cpp ├── result │ └── ocean_monument │ │ ├── (Pseudo) Triple.txt │ │ ├── Double(96 blocks distance).txt │ │ └── README.md ├── test │ ├── test_base.h │ └── utils_test.cpp ├── utils.cpp └── utils.h ├── be_finder.cpp ├── be_finder.h ├── be_random.cpp ├── be_random.h ├── main.cpp ├── structure.cpp ├── structure.h ├── tools.cpp └── tools.h /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | .idea 4 | build -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cubiomes"] 2 | path = cubiomes 3 | url = https://github.com/Cubitect/cubiomes 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.10) 2 | project(mcbe_structue) 3 | set(CMAKE_CXX_STANDARD 17) 4 | 5 | set(BIOME_LIB_NAME cubiomes) 6 | set(BE_STRUCTUR_LIB_NAME bestructure) 7 | include_directories( 8 | PUBLIC 9 | ${PROJECT_SOURCE_DIR}/cubiomes 10 | ${PROJECT_SOURCE_DIR}/ 11 | ) 12 | add_library( 13 | ${BIOME_LIB_NAME} 14 | cubiomes/util.c 15 | cubiomes/noise.c 16 | cubiomes/rng.h 17 | cubiomes/layers.c 18 | cubiomes/generator.c 19 | cubiomes/finders.c 20 | cubiomes/biome_tree.c 21 | ) 22 | 23 | 24 | add_library( 25 | ${BE_STRUCTUR_LIB_NAME} 26 | be_random.cpp 27 | tools.cpp 28 | be_finder.cpp 29 | structure.cpp 30 | 31 | ) 32 | target_link_libraries(${BE_STRUCTUR_LIB_NAME} ${BIOME_LIB_NAME}) 33 | 34 | 35 | add_executable(test main.cpp) 36 | target_link_libraries(test ${BE_STRUCTUR_LIB_NAME}) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 1.18+ is in refactoring !!! -------------------------------------------------------------------------------- /backup/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(cubiomes) 3 | set(CMAKE_CXX_STANDARD 17) 4 | #add_compile_options(-O3) 5 | include_directories(cubiomes .) 6 | 7 | set(CUBIOMES_NAME cubiomes-be) 8 | set(FINDER_NAME be-structure-finder) 9 | #预编译cubiomes-bedrock 10 | add_library(${CUBIOMES_NAME} 11 | STATIC 12 | cubiomes/generator.c 13 | cubiomes/layers.c 14 | cubiomes/mcrandom.c 15 | cubiomes/util.c 16 | ) 17 | 18 | add_library(${FINDER_NAME} 19 | ../structure.cpp 20 | ../be_random.cpp 21 | utils.cpp 22 | finder.cpp 23 | ../be_finder.cpp 24 | ) 25 | target_link_libraries(${FINDER_NAME} ${CUBIOMES_NAME}) 26 | #add_executable(speedrun speedrunseed.c) 27 | add_executable(main main.cpp) 28 | target_link_libraries(main ${FINDER_NAME}) 29 | 30 | function(create_test name files) 31 | add_executable(${name} 32 | ${files} 33 | ${PROJECT_SOURCE_DIR}/test/test_base.h 34 | ) 35 | target_include_directories( 36 | ${name} 37 | PUBLIC 38 | ${PROJECT_SOURCE_DIR}/cubiomes 39 | ${PROJECT_SOURCE_DIR} 40 | ${PROJECT_SOURCE_DIR}/test 41 | ) 42 | target_link_libraries(${name} ${FINDER_NAME}) 43 | endfunction(create_test) 44 | create_test(utils_test test/utils_test.cpp) 45 | 46 | 47 | -------------------------------------------------------------------------------- /backup/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 重构中!!! 当前版本暂时无法使用!! 3 | # Minecraft Bedrock Structure Finder 4 | 5 | Minecraft bedrock edition structure finders(updating) 6 | 7 | ## Progress 8 | 9 | - [X] WorldSpawn 10 | - [X] Village, 11 | - [X] Stronghold, 12 | - [ ] Mineshaft, 13 | - [X] DesertTemple, 14 | - [X] WitchHut, 15 | - [X] JungleTemple, 16 | - [X] Igloo, 17 | - [X] OceanMonument, 18 | - [ ] OceanRuin, 19 | - [X] WoodlandMansion, 20 | - [ ] Shipwreck, 21 | - [X] RuindPortal, 22 | - [X] BuriedTreasure, 23 | - [X] PillagerOutpost, 24 | - [X] NetherFortress, 25 | - [X] Bastion, 26 | - [ ] Endcity 27 | - [ ] ... 28 | 29 | 30 | ## Credit 31 | - [github.com/reedacartwright/cubiomes](github.com/reedacartwright/cubiomes) 32 | - Thanks [origin0110](https://github.com/origin0110) and [OEOTYAN](https://github.com/OEOTYAN) for many suggestions on code and algorithm optimization 33 | - Thanks WANG for providing 3700X 34 | -------------------------------------------------------------------------------- /backup/cubiomes/.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=C 2 | *.h linguist-language=C 3 | 4 | -------------------------------------------------------------------------------- /backup/cubiomes/.gitignore: -------------------------------------------------------------------------------- 1 | find_compactbiomes 2 | find_quadhuts 3 | .cproject 4 | .project 5 | docs/LayerSummary.aux 6 | docs/LayerSummary.log 7 | docs/LayerSummary.synctex.gz 8 | docs/LayerSummary.toc 9 | *.o 10 | *.a 11 | 12 | -------------------------------------------------------------------------------- /backup/cubiomes/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Cubitect 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 | -------------------------------------------------------------------------------- /backup/cubiomes/LayerSummary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedrock-dev/MCBEStructureFinder/14d79b8c92f6d67d1e4556e535b8babef3cc91b9/backup/cubiomes/LayerSummary.pdf -------------------------------------------------------------------------------- /backup/cubiomes/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | ARFLAGS = cr 4 | override LDFLAGS = -lm 5 | override CFLAGS += -Wall -Wextra -fwrapv 6 | 7 | ifeq ($(OS),Windows_NT) 8 | override CFLAGS += -D_WIN32 9 | RM = del 10 | else 11 | override LDFLAGS += -pthread 12 | #RM = rm 13 | endif 14 | 15 | .PHONY : all debug release native libcubiomes clean 16 | 17 | all: release 18 | 19 | debug: CFLAGS += -DDEBUG -O0 -ggdb3 20 | debug: libcubiomes 21 | release: CFLAGS += -O3 22 | release: libcubiomes 23 | native: CFLAGS += -O3 -march=native 24 | native: libcubiomes 25 | 26 | ifeq ($(OS),Windows_NT) 27 | else 28 | libcubiomes: CFLAGS += -fPIC 29 | endif 30 | 31 | libcubiomes: libcubiomes.a 32 | 33 | libcubiomes.a: layers.o generator.o finders.o util.o mcrandom.o 34 | $(AR) $(ARFLAGS) $@ $^ 35 | 36 | finders.o: finders.c finders.h 37 | $(CC) -c $(CFLAGS) $< 38 | 39 | generator.o: generator.c generator.h 40 | $(CC) -c $(CFLAGS) $< 41 | 42 | layers.o: layers.c layers.h 43 | $(CC) -c $(CFLAGS) $< 44 | 45 | util.o: util.c util.h 46 | $(CC) -c $(CFLAGS) $< 47 | 48 | mcrandom.o: mcrandom.c mcrandom.h 49 | $(CC) -c $(CFLAGS) $< 50 | 51 | clean: 52 | $(RM) *.o libcubiomes.a 53 | 54 | -------------------------------------------------------------------------------- /backup/cubiomes/README.md: -------------------------------------------------------------------------------- 1 | # cubiomes 2 | 3 | Cubiomes is a standalone library, written in C, that mimics the biome and feature generation of Minecraft Java Edition. 4 | It is intended as a powerful tool to devise very fast, custom seed finding applications and large scale map viewers with minimal memory usage. 5 | 6 | 7 | #### Cubiomes-Viewer 8 | 9 | If you want to get started without coding there is now also a [graphical application](https://github.com/Cubitect/cubiomes-viewer) based on this library. 10 | 11 | 12 | #### Audience 13 | 14 | You should be familiar with the C programming language, also a basic understanding of the Minecraft biome generation process would be helpful. 15 | 16 | 17 | ## Getting Started 18 | 19 | This section is meant to give you a quick starting point with small example programs if you want to use this library to find your own biome dependent features. 20 | 21 | ### Biome Generator 22 | 23 | Let's create a simple program called `find_jedge.c` which tests seeds for a Junge Edge biome at a predefined location. 24 | 25 | ```C 26 | // check the biome at a block position 27 | #include "finders.h" 28 | #include 29 | 30 | int main() 31 | { 32 | // Initialize a stack of biome layers that reflects the biome generation of 33 | // Minecraft 1.17 34 | LayerStack g; 35 | setupGenerator(&g, MC_1_17); 36 | 37 | // seeds are internally represented as unsigned 64-bit integers 38 | uint64_t seed; 39 | Pos pos = {0,0}; // block position to be checked 40 | 41 | for (seed = 0; ; seed++) 42 | { 43 | // Go through the layers in the layer stack and initialize the seed 44 | // dependent aspects of the generator. 45 | applySeed(&g, seed); 46 | 47 | // To get the biome at single block position we can use getBiomeAtPos(). 48 | int biomeID = getBiomeAtPos(&g, pos); 49 | if (biomeID == jungle_edge) 50 | break; 51 | } 52 | 53 | printf("Seed %" PRId64 " has a Junge Edge biome at block position " 54 | "(%d, %d).\n", (int64_t) seed, pos.x, pos.z); 55 | 56 | return 0; 57 | } 58 | ``` 59 | 60 | You can compile this code either by directly adding a target to the makefile, or you can compile and link to a cubiomes archive: 61 | ``` 62 | $ cd cubiomes 63 | $ make libcubiomes 64 | ``` 65 | To compile, and link the cubiomes library you can use one of 66 | ``` 67 | $ gcc find_jedge.c libcubiomes.a -fwrapv -lm # static 68 | $ gcc find_jedge.c -L. -lcubiomes -fwrapv -lm # dynamic 69 | ``` 70 | Both commands assume that your source code is saved as `find_jedge.c` in the cubiomes working directory. If your makefile is configured to use pthreads you also may need to add the `-lpthread` option to the compiler. 71 | The option `-fwrapv` enforces two's complement for signed integer overflow, which this library relies on. It is not strictly necessary for this example as the library should already be compiled with this flag, but it is good practice to prevent undefined behaviour. 72 | Running the program should output: 73 | ``` 74 | $ ./a.out 75 | Seed 615 has a Junge Edge biome at block position (0, 0). 76 | ``` 77 | 78 | We can also generate the biomes for a rectangular region using `genArea()` which also offers control over the entry layer, see the layer documentation for more information. 79 | 80 | ```C 81 | // generate an image of the world 82 | #include "generator.h" 83 | #include "util.h" 84 | 85 | int main() 86 | { 87 | unsigned char biomeColors[256][3]; 88 | 89 | // Initialize a color map for biomes. 90 | initBiomeColors(biomeColors); 91 | 92 | // Initialize a stack of biome layers. 93 | LayerStack g; 94 | setupGenerator(&g, MC_1_17); 95 | // Extract the desired layer. 96 | Layer *layer = &g.layers[L_SHORE_16]; 97 | 98 | uint64_t seed = 1661454332289LL; 99 | int areaX = -60, areaZ = -60; 100 | unsigned int areaWidth = 120, areaHeight = 120; 101 | unsigned int scale = 4; 102 | unsigned int imgWidth = areaWidth*scale, imgHeight = areaHeight*scale; 103 | 104 | // Allocate a sufficient buffer for the biomes and for the image pixels. 105 | int *biomeIds = allocCache(layer, areaWidth, areaHeight); 106 | unsigned char *rgb = (unsigned char *) malloc(3*imgWidth*imgHeight); 107 | 108 | // Apply the seed only for the required layers and generate the area. 109 | setLayerSeed(layer, seed); 110 | genArea(layer, biomeIds, areaX, areaZ, areaWidth, areaHeight); 111 | 112 | // Map the biomes to a color buffer and save to an image. 113 | biomesToImage(rgb, biomeColors, biomeIds, areaWidth, areaHeight, scale, 2); 114 | savePPM("biomes_at_layer.ppm", rgb, imgWidth, imgHeight); 115 | 116 | // Clean up. 117 | free(biomeIds); 118 | free(rgb); 119 | 120 | return 0; 121 | } 122 | ``` 123 | 124 | 125 | #### Layer Documentation 126 | 127 | There is a reference document for the generator layers which contains a summary for most generator layers and their function within the generation process (a little out of date, since 1.13). 128 | 129 | 130 | #### Biome Filters 131 | 132 | Biome filters provide a way of generating an area, but only if that area contains certain biomes. Rather than generating an area first and then checking that it contains what we want, the requirements are tested during the generation process. This can be a dramatic speed up, particularly if we require several wildly different biomes. 133 | 134 | ```C 135 | // find seeds that have certain biomes near the origin 136 | #include "finders.h" 137 | #include 138 | 139 | int main() 140 | { 141 | int mc = MC_1_17; 142 | LayerStack g; 143 | BiomeFilter filter; 144 | 145 | setupGenerator(&g, mc); 146 | 147 | // Define the required biomes. 148 | int wanted[] = { 149 | dark_forest, 150 | ice_spikes, 151 | mushroom_fields, 152 | }; 153 | filter = setupBiomeFilter(wanted, sizeof(wanted) / sizeof(int)); 154 | 155 | int x = -200, z = -200, w = 400, h = 400; 156 | int entry = L_VORONOI_1; 157 | int *area = allocCache(&g.layers[entry], w, h); 158 | 159 | printf("Searching...\n"); 160 | uint64_t seed; 161 | for (seed = 0; ; seed++) 162 | if (checkForBiomes(&g, entry, area, seed, x, z, w, h, filter, 1) > 0) 163 | break; 164 | 165 | printf("Seed %" PRId64 " has the required biomes in (%d, %d) - (%d, %d).\n", 166 | (int64_t) seed, x, z, x+w, z+h); 167 | 168 | free(area); 169 | return 0; 170 | } 171 | ``` 172 | 173 | 174 | ### Structure Generation 175 | 176 | The generation of structures can usually be regarded as a two stage process: generation attempts and biome checks. For most structures, Minecraft divides the world into a grid of regions (usually 32x32 chunks) and performs one generation attempt in each. We can use `getStructurePos` to get the position of such a generation attempt and then test whether a structure will actually generate there with `isViableStructurePos`, however, this is more expensive to compute (a few µsec rather than nsec). 177 | 178 | ```C 179 | // find a seed with a certain structure at the origin chunk 180 | #include "finders.h" 181 | #include 182 | 183 | int main() 184 | { 185 | int structType = Outpost; 186 | int mc = MC_1_17; 187 | 188 | LayerStack g; 189 | setupGenerator(&g, mc); 190 | 191 | uint64_t lower48; 192 | for (lower48 = 0; ; lower48++) 193 | { 194 | // The structure position depends only on the region coordinates and 195 | // the lower 48-bits of the world seed. 196 | Pos p; 197 | if (!getStructurePos(structType, mc, lower48, 0, 0, &p)) 198 | continue; 199 | 200 | // Look for a seed with the structure at the origin chunk. 201 | if (p.x >= 16 || p.z >= 16) 202 | continue; 203 | 204 | // Look for a full 64-bit seed with viable biomes. 205 | uint64_t upper16; 206 | for (upper16 = 0; upper16 < 0x10000; upper16++) 207 | { 208 | uint64_t seed = lower48 | (upper16 << 48); 209 | if (isViableStructurePos(structType, mc, &g, seed, p.x, p.z)) 210 | { 211 | printf("Seed %" PRId64 " has a Pillager Outpost at (%d, %d).\n", 212 | (int64_t) seed, p.x, p.z); 213 | return 0; 214 | } 215 | } 216 | } 217 | } 218 | ``` 219 | 220 | #### Quad-Witch-Huts 221 | 222 | A commonly desired feature are Quad-Witch-Huts or similar multi-structure clusters. To test for these types of seeds we can look a little deeper into how the generation attemps are determined. Notice that the positions depend only on the structure type, region coordinates and the lower 48 bits of the seed. Also, once we have found a seed with the desired generation attemps, we can move them around by transforming the 48-bit seed using `moveStructure`. This means there is a set of seed bases which can function as a starting point to generate all other seeds with similar structure placement. 223 | 224 | The function `searchAll48` can be used to find a complete set of 48-bit seed bases for a custom criterion. Given that in general it can take a very long time to check all 2^48 seeds (days or weeks), the function provides some functionality to save the results to disk which can be loaded again using `loadSavedSeeds`. Luckly, in some cases it is possible to reduce the search space even further. For Swamp Huts and structures with a similar structure configuration there are only a handfull of constellations where the structures are close enough together to run simultaneously. Conveniently, these constellations differ uniquely at the lower 20 bits. (This is hard to prove, or at least I haven't found a riggerous proof that doesn't rely on brute forcing.) By specifying a list of lower 20-bit values we can reduce the search space to the order of 2^28, which can be checked in a reasonable amount of time. 225 | 226 | 227 | ```C 228 | // find seeds with a quad-witch-hut about the origin 229 | #include "finders.h" 230 | #include 231 | 232 | int check(uint64_t s48, void *data) 233 | { 234 | const StructureConfig sconf = *(const StructureConfig*) data; 235 | return isQuadBase(sconf, s48 - sconf.salt, 128); 236 | } 237 | 238 | int main() 239 | { 240 | int styp = Swamp_Hut; 241 | int mc = MC_1_17; 242 | uint64_t basecnt = 0; 243 | uint64_t *bases = NULL; 244 | int threads = 8; 245 | LayerStack g; 246 | 247 | StructureConfig sconf; 248 | getStructureConfig(styp, mc, &sconf); 249 | 250 | printf("Preparing seed bases...\n"); 251 | // Get all 48-bit quad-witch-hut bases, but consider only the best 20-bit 252 | // constellations where the structures are the closest together. 253 | int err = searchAll48( 254 | &bases, &basecnt, NULL, threads, 255 | low20QuadIdeal, sizeof(low20QuadIdeal) / sizeof(uint64_t), 20, 256 | check, &sconf 257 | ); 258 | 259 | if (err || !bases) 260 | { 261 | printf("Failed to generate seed bases.\n"); 262 | exit(1); 263 | } 264 | 265 | setupGenerator(&g, mc); 266 | 267 | uint64_t i; 268 | for (i = 0; i < basecnt; i++) 269 | { 270 | // The quad bases by themselves have structures in regions (0,0)-(1,1) 271 | // so we can move them by -1 regions to have them around the origin. 272 | uint64_t s48 = moveStructure(bases[i] - sconf.salt, -1, -1); 273 | 274 | Pos pos[4]; 275 | getStructurePos(styp, mc, s48, -1, -1, &pos[0]); 276 | getStructurePos(styp, mc, s48, -1, 0, &pos[1]); 277 | getStructurePos(styp, mc, s48, 0, -1, &pos[2]); 278 | getStructurePos(styp, mc, s48, 0, 0, &pos[3]); 279 | 280 | uint64_t high; 281 | for (high = 0; high < 0x10000; high++) 282 | { 283 | uint64_t seed = s48 | (high << 48); 284 | 285 | if (isViableStructurePos(styp, mc, &g, seed, pos[0].x, pos[0].z) && 286 | isViableStructurePos(styp, mc, &g, seed, pos[1].x, pos[1].z) && 287 | isViableStructurePos(styp, mc, &g, seed, pos[2].x, pos[2].z) && 288 | isViableStructurePos(styp, mc, &g, seed, pos[3].x, pos[3].z)) 289 | { 290 | printf("%" PRId64 "\n", (int64_t) seed); 291 | } 292 | } 293 | } 294 | 295 | free(bases); 296 | return 0; 297 | } 298 | ``` 299 | 300 | #### Strongholds and Spawn 301 | 302 | Strongholds as well as the world spawn point actually search until they find a suitable location, rather than checking a single spot like most other structures. This causes them to be particularly performance expensive to find. Furthermore, the positions of stongholds have to be generated in a certain order, which can be done in an iterator fashion with `initFirstStronghold` and `nextStronghold`. For the world spawn, the generation starts with a search for a suitable biome near the origin, but will continue until a grass or podzol block is found. There is no reliable way of checking actual blocks, which means the search relies on a statistic, matching grass presence to biomes. Alternatively, we can simply use `estimateSpawn` and terminate the search after the first biome check and assume that grass is near by. 303 | 304 | 305 | ```C 306 | // find spawn and the first N strongholds 307 | #include "finders.h" 308 | #include 309 | 310 | int main() 311 | { 312 | int mc = MC_1_17; 313 | uint64_t seed = 3055141959546LL; 314 | 315 | // Only the first stronghold has a position which can be estimated 316 | // (+/-112 blocks) without biome check. 317 | StrongholdIter sh; 318 | Pos pos = initFirstStronghold(&sh, mc, seed); 319 | 320 | printf("Seed: %" PRId64 "\n", (int64_t) seed); 321 | printf("Estimated position of first stronghold: (%d, %d)\n", pos.x, pos.z); 322 | 323 | // The finders for the strongholds and spawn require that the seed is 324 | // applied to the generator beforehand. 325 | LayerStack g; 326 | setupGenerator(&g, mc); 327 | applySeed(&g, seed); 328 | 329 | pos = getSpawn(mc, &g, NULL, seed); 330 | printf("Spawn: (%d, %d)\n", pos.x, pos.z); 331 | 332 | int i, N = 12; 333 | for (i = 1; i <= N; i++) 334 | { 335 | if (nextStronghold(&sh, &g, NULL) <= 0) 336 | break; 337 | printf("Stronghold #%-3d: (%6d, %6d)\n", i, sh.pos.x, sh.pos.z); 338 | } 339 | 340 | return 0; 341 | } 342 | ``` 343 | 344 | 345 | 346 | 347 | 348 | -------------------------------------------------------------------------------- /backup/cubiomes/docs/LayerSummary.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{listings} 3 | \usepackage{xcolor} 4 | \usepackage{graphicx} 5 | \usepackage{url} 6 | \usepackage{pdfpages} 7 | \usepackage{makecell} 8 | \usepackage{tabularx} 9 | \usepackage{amsmath} 10 | \usepackage{amssymb} 11 | \usepackage{multirow} 12 | \usepackage{array} 13 | 14 | \title{Summary of the Biome Generation in \\ Minecraft 1.7 - 1.12} 15 | 16 | \author{Cubitect} 17 | 18 | \begin{document} 19 | 20 | \maketitle 21 | 22 | \begin{abstract} 23 | This document is designed to provide an overview of how Minecraft biome generation works and how we may efficiently find seeds with desired properties. 24 | \end{abstract} 25 | 26 | \newpage 27 | 28 | \tableofcontents 29 | 30 | 31 | 32 | \newpage 33 | 34 | 35 | \section{Biome Generator Layers} 36 | 37 | Minecraft biome generation occurs in layers. Many of these layers are chained together inside the generator, such that the output from one becomes the input for the next. A flowchart of this can be found on the next page. 38 | 39 | Each layer applies certain modifications to a map of integers, which change their use throughout the generation process. Initially the map only contains values 0 or 1, representing ocean or land masses. Later in the generator they represent temperature categories, until they are finally replaced by the actual biome IDs. 40 | 41 | Some of the layers resize the output of the previous layer. These Zoom-layers therefore change how much area is represented by a map entry. I will refer to this as "scale". For instance, 1:256 should be read as: one map entry ends up as an area of 256x256 blocks in the world. 42 | 43 | \setcounter{subsection}{-1} 44 | \subsection{Seed Finding} 45 | 46 | When constructing a seed finder, it may be useful to stop the generation at an earlier layer. For example if we require a swamp to be located near a given position, then we might want to generate up to layer 19: Biome first, and then check on a 1:256 scale if there is a swamp in the area. This is not enough to confirm that there will be a swamp at the given position, but we can rule out seeds that definitely don't have a swamp anywhere near the area. If the seed passes this cheap test, then we can go through the full expensive generation process and directly check the position for a swamp. 47 | 48 | Usually it is not practical to continue the search from a terminated generation and we have to start over again. The reason for this is that most layers require an additional 1 wide boarder from the previous layer, so the map sizes don't match up. 49 | 50 | Another more involved, but very powerful way of creating early knock-out criteria is to check if there is a some condition in the layer chain that is independent of the rest of the biomes. For instance in the case of finding a swamp, we can notice that there is a pseudo-random number check in layer 19: Biome, that converts Lush temperature climates to swamplands. However, the pseudo-random number generator is seeded by a combination of the position and the world seed, so we can make sure the random number output gives the required value without going through the rest of the layers. The more expensive generator can afterwards be used to make sure that a Lush climate is actually present at that position. 51 | 52 | 53 | In the summary below in sections 1.1 -- 1.44 I have laid out some of the properties of each layer, such as the scale of the layer and the possible values for the map entries with their respective average probability of occurrence (Note: these are estimates and may vary). When constructing a seed finder these values can be used as a reference to determine reasonable cut-off points for the generator. 54 | 55 | 56 | \includepdf[pages={1}]{layers.pdf} 57 | 58 | 59 | \subsection{Layer 1: Island} 60 | \begin{tabular}{|l|l|l|}\hline 61 | Scale: & \multicolumn{2}{|l|}{1:4096} \\\hline\hline 62 | Value & Type & Occurrence \\\hline 63 | 0 & Ocean & 90.0\%\\\hline 64 | 1 & Land & 10.0\%\\\hline 65 | \end{tabular} 66 | 67 | \subsection{Layer 2: Zoom} 68 | \begin{tabular}{|l|l|l|}\hline 69 | Scale: & \multicolumn{2}{|l|}{1:2048} \\\hline\hline 70 | Value & Type & Occurrence \\\hline 71 | 0 & Ocean & 90.0\%\\\hline 72 | 1 & Land & 10.0\%\\\hline 73 | \end{tabular} 74 | 75 | \subsection{Layer 3: Add Island} 76 | \begin{tabular}{|l|l|l|}\hline 77 | Scale: & \multicolumn{2}{|l|}{1:2048} \\\hline\hline 78 | Value & Type & Occurrence \\\hline 79 | 0 & Ocean & 84.3\%\\\hline 80 | 1 & Land & 15.7\%\\\hline 81 | \end{tabular} 82 | 83 | \subsection{Layer 4: Zoom} 84 | \begin{tabular}{|l|l|l|}\hline 85 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 86 | Value & Type & Occurrence \\\hline 87 | 0 & Ocean & 84.9\%\\\hline 88 | 1 & Land & 15.1\%\\\hline 89 | \end{tabular} 90 | 91 | \subsection{Layer 5: Add Island} 92 | \begin{tabular}{|l|l|l|}\hline 93 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 94 | Value & Type & Occurrence \\\hline 95 | 0 & Ocean & 81.4\%\\\hline 96 | 1 & Land & 18.6\%\\\hline 97 | \end{tabular} 98 | 99 | \subsection{Layer 6: Add Island} 100 | \begin{tabular}{|l|l|l|}\hline 101 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 102 | Value & Type & Occurrence \\\hline 103 | 0 & Ocean & 77.5\%\\\hline 104 | 1 & Land & 22.5\%\\\hline 105 | \end{tabular} 106 | 107 | \subsection{Layer 7: Add Island} 108 | \begin{tabular}{|l|l|l|}\hline 109 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 110 | Value & Type & Occurrence \\\hline 111 | 0 & Ocean & 73.4\%\\\hline 112 | 1 & Land & 26.6\%\\\hline 113 | \end{tabular} 114 | 115 | \subsection{Layer 8: Remove Too Much Ocean} 116 | \begin{tabular}{|l|l|l|}\hline 117 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 118 | Value & Type & Occurrence \\\hline 119 | 0 & Ocean & 49.4\%\\\hline 120 | 1 & Land & 50.6\%\\\hline 121 | \end{tabular} 122 | 123 | 124 | \subsection{Layer 9: Add Snow} 125 | \begin{tabular}{|l|l|l|}\hline 126 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 127 | Value & Type & Occurrence \\\hline 128 | 0 & Ocean & 49.4\%\\\hline 129 | 1 & Warm & 33.7\%\\\hline 130 | 3 & Cold & 4.8\%\\\hline 131 | 4 & Freezing & 12.4\%\\\hline 132 | \end{tabular} 133 | 134 | \medskip\noindent 135 | Changes some of the land starting points to Cold and Freezing. 136 | 137 | \subsection{Layer 10: Add Island} 138 | \begin{tabular}{|l|l|l|}\hline 139 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 140 | Value & Type & Occurrence \\\hline 141 | 0 & Ocean & 33.8\%\\\hline 142 | 1 & Warm & 37.6\%\\\hline 143 | 3 & Cold & 4.8\%\\\hline 144 | 4 & Freeing & 23.9\%\\\hline 145 | \end{tabular} 146 | 147 | \medskip\noindent 148 | Spreads out the continental areas, decreasing the amount of ocean. 149 | 150 | \subsection{Layer 11: Edge, Cool/Warm} 151 | \begin{tabular}{|l|l|l|}\hline 152 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 153 | Value & Type & Occurrence \\\hline 154 | 0 & Ocean & 33.8\%\\\hline 155 | 1 & Warm & 13.6\%\\\hline 156 | 2 & Lush & 23.9\%\\\hline 157 | 3 & Cold & 4.8\%\\\hline 158 | 4 & Freezing & 23.9\%\\\hline 159 | \end{tabular} 160 | 161 | \medskip\noindent 162 | Changes Warm(1) lands which are adjacent to Cold(3) or Freezing(4) temperatures to Lush(2). 163 | 164 | \subsection{Layer 12: Edge, Heat/Ice} 165 | \begin{tabular}{|l|l|l|}\hline 166 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 167 | Value & Type & Occurrence \\\hline 168 | 0 & Ocean & 33.8\%\\\hline 169 | 1 & Warm & 13.6\%\\\hline 170 | 2 & Lush & 23.9\%\\\hline 171 | 3 & Cold & 23.9\%\\\hline 172 | 4 & Freezing & 4.8\%\\\hline 173 | \end{tabular} 174 | 175 | \medskip\noindent 176 | Changes Freezing(4) lands which are adjacent to Warm(1) or Lush(2) temperatures to Cold(3). 177 | 178 | \subsection{Layer 13: Edge, Special} 179 | \begin{tabular}{|l|l|l|}\hline 180 | Scale: & \multicolumn{2}{|l|}{1:1024} \\\hline\hline 181 | Value & Type & Occurrence \\\hline 182 | 0 & Ocean & 33.8\%\\\hline 183 | 1 & Warm & 12.5\%\\\hline 184 | 2 & Lush & 22.1\%\\\hline 185 | 3 & Cold & 22.1\%\\\hline 186 | 4 & Freezing & 4.4\%\\\hline 187 | - & Special & 5.1\% / 60\\\hline 188 | \end{tabular} 189 | 190 | \medskip\noindent 191 | Marks every 1 in 13 lands (non-ocean) as special, by adding a 4-bit number in 0x0F00 to the value. 192 | 193 | 194 | \subsection{Layer 14: Zoom} 195 | \begin{tabular}{|l|l|l|}\hline 196 | Scale: & \multicolumn{2}{|l|}{1:512} \\\hline\hline 197 | Value & Type & Occurrence \\\hline 198 | 0 & Ocean & 35.6\%\\\hline 199 | 1 & Warm & 12.2\%\\\hline 200 | 2 & Lush & 21.9\%\\\hline 201 | 3 & Cold & 21.9\%\\\hline 202 | 4 & Freezing & 4.2\%\\\hline 203 | - & Special & 4.2\% / 60\\\hline 204 | \end{tabular} 205 | 206 | \subsection{Layer 15: Zoom} 207 | \begin{tabular}{|l|l|l|}\hline 208 | Scale: & \multicolumn{2}{|l|}{1:256} \\\hline\hline 209 | Value & Type & Occurrence \\\hline 210 | 0 & Ocean & 35.6\%\\\hline 211 | 1 & Warm & 11.9\%\\\hline 212 | 2 & Lush & 21.9\%\\\hline 213 | 3 & Cold & 21.9\%\\\hline 214 | 4 & Freezing & 4.2\%\\\hline 215 | - & Special & 4.5\% / 60\\\hline 216 | \end{tabular} 217 | 218 | \subsection{Layer 16: Add Island} 219 | \begin{tabular}{|l|l|l|}\hline 220 | Scale: & \multicolumn{2}{|l|}{1:256} \\\hline\hline 221 | Value & Type & Occurrence \\\hline 222 | 0 & Ocean & 31.4\%\\\hline 223 | 1 & Warm & 12.7\%\\\hline 224 | 2 & Lush & 22.4\%\\\hline 225 | 3 & Cold & 22.8\%\\\hline 226 | 4 & Freezing & 6.2\%\\\hline 227 | - & Special & 4.5\% / 60\\\hline 228 | \end{tabular} 229 | 230 | 231 | \subsection{Layer 17: Add Mushroom Island} 232 | \begin{tabular}{|l|l|l|l|}\hline 233 | Scale: & \multicolumn{3}{|l|}{1:256} \\\hline\hline 234 | Value & Type & \multicolumn{2}{l|}{Occurrence} \\\hline 235 | 0 & Ocean & \multicolumn{2}{l|}{31.4\%}\\\hline 236 | 1 & Warm & \multicolumn{2}{l|}{12.8\%}\\\hline 237 | 2 & Lush & \multicolumn{2}{l|}{22.5\%}\\\hline 238 | 3 & Cold & \multicolumn{2}{l|}{22.7\%}\\\hline 239 | 4 & Freezing & \multicolumn{2}{l|}{6.08\%}\\\hline 240 | 14 & Mushroom & \multicolumn{2}{l|}{0.0773\%}\\\hline\hline 241 | 242 | \makecell[l]{ $(n<<8)+1$ \\ with $n = $ \\ $1, 4, 7, 10, 13$ } & - & 243 | \makecell[l]{0.0690\% \\each} & \multirow{5}{*}{0.90\%}\\\cline{1-3} 244 | 245 | \makecell[l]{ $(n<<8)+1$ \\ with $n = $ \\ $2, 3, 5, 6, 8, 9,$ \\ $11, 12, 14, 15$ } & - & \makecell[l]{0.0553\% \\ each} & \\\hline\hline 246 | 247 | \makecell[l]{ $(n<<8)+2$ \\ with $n = $ \\ $1, 4, 7, 10, 13$ } & - & 248 | \makecell[l]{0.1236\% \\ each} & \multirow{5}{*}{1.56\%}\\\cline{1-3} 249 | 250 | \makecell[l]{ $(n<<8)+2$ \\ with $n = $ \\ $2, 3, 5, 6, 8, 9,$ \\ $11, 12, 14, 15$ } & - & \makecell[l]{0.0961\% \\ each} & \\\hline\hline 251 | 252 | \makecell[l]{ $(n<<8)+3$ \\ with $n = $ \\ $1, 4, 7, 10, 13$ } & - & 253 | \makecell[l]{0.1078\% \\ each} & \multirow{5}{*}{1.58\%}\\\cline{1-3} 254 | 255 | \makecell[l]{ $(n<<8)+3$ \\ with $n = $ \\ $2, 3, 5, 6, 8, 9,$ \\ $11, 12, 14, 15$ } & - & 256 | \makecell[l]{0.1037\% \\ each} & \\\hline\hline 257 | 258 | \makecell[l]{ $(n<<8)+4$ \\ with $n = $ \\ $1, 4, 7, 10, 13$ } & - & 259 | \makecell[l]{0.0212\% \\ each} & \multirow{5}{*}{0.32\%}\\\cline{1-3} 260 | 261 | \makecell[l]{ $(n<<8)+4$ \\ with $n = $ \\ $2, 3, 5, 6, 8, 9,$ \\ $11, 12, 14, 15$ } & - & 262 | \makecell[l]{0.0212\% \\ each} & \\\hline 263 | 264 | \end{tabular} 265 | 266 | \medskip\noindent 267 | Changes every 100th Ocean (adjacent to more Ocean) to Mushroom Island. The special land types are written out in full in the table above. (Note "$<<$" represents a left bit shit.) Added together, the special types make up an average of about 4.37\% of the area. 268 | 269 | 270 | \subsection{Layer 18: Deep Ocean} 271 | \begin{tabular}{|l|l|l|}\hline 272 | Scale: & \multicolumn{2}{|l|}{1:256} \\\hline\hline 273 | Value & Type & Occurrence \\\hline 274 | 0 & Ocean & 22.0\%\\\hline 275 | 1 & Warm & 12.8\%\\\hline 276 | 2 & Lush & 22.5\%\\\hline 277 | 3 & Cold & 22.7\%\\\hline 278 | 4 & Freezing & 6.1\%\\\hline 279 | 14 & Mushroom & 0.0773\%\\\hline 280 | 24 & Deep Ocean & 9.4\%\\\hline 281 | - & Special & 4.4\% / 60\\\hline 282 | \end{tabular} 283 | 284 | \medskip\noindent 285 | Changes any Ocean which is surrounded by more Ocean to Deep Ocean.\\ 286 | (Special lands still have the same statistics as shown for Layer 17.) 287 | 288 | 289 | \subsection{Layer 19: Biome} 290 | \begin{tabular}{|l|l|l|}\hline 291 | Scale: & \multicolumn{2}{|l|}{1:256} \\\hline\hline 292 | Value & Type & Occurrence \\\hline 293 | 0 & ocean & 22.0\%\\\hline 294 | 1 & plains & 11.6\%\\\hline 295 | 2 & desert & 6.41\%\\\hline 296 | 3 & extremeHills & 9.44\%\\\hline 297 | 4 & forest & 9.43\%\\\hline 298 | 5 & taiga & 5.68\%\\\hline 299 | 6 & swampland & 3.75\%\\\hline 300 | 12 & icePlains & 4.80\%\\\hline 301 | 14 & mushroomIsland & 0.0773\%\\\hline 302 | 21 & jungle & 1.58\%\\\hline 303 | 24 & deepOcean & 9.38\%\\\hline 304 | 27 & birchForest & 3.75\%\\\hline 305 | 29 & roofedForest & 3.75\%\\\hline 306 | 30 & coldTaiga & 1.60\%\\\hline 307 | 32 & megaTaiga & 1.58\%\\\hline 308 | 35 & savanna & 4.28\%\\\hline 309 | 38 & mesaPlateau\_F & 0.598\%\\\hline 310 | 39 & mesaPlateau & 0.299\%\\\hline 311 | \end{tabular} 312 | 313 | \medskip\noindent 314 | Assigns the actual biome IDs to the lands, based on the temperature category of the land. To be more specific the selection criteria are: 315 | 316 | \begin{tabular}{l c c l} 317 | 318 | Temperature & & Weight & Biome \\\hline\hline 319 | 320 | Warm & $\longrightarrow$ & 321 | \makecell[c]{1/2 \\ 1/3 \\ 1/6} & 322 | \makecell[l]{desert \\ savanna \\ plains} \\\hline 323 | 324 | Warm, special & $\longrightarrow$ & 325 | \makecell[c]{1/3 \\ 2/3} & 326 | \makecell[l]{mesaPlateau \\ mesaPlateau\_F} \\\hline 327 | 328 | Lush & $\longrightarrow$ & 329 | \makecell[c]{1/6 \\ 1/6 \\ 1/6 \\ 1/6 \\ 1/6 \\ 1/6} & 330 | \makecell[l]{forest \\ roofedForest \\ extremeHills \\ plains \\ birchForest \\ swampland} \\\hline 331 | 332 | Lush, special & $\longrightarrow$ & 333 | \makecell[c]{1/1} & 334 | jungle \\\hline 335 | 336 | Cold & $\longrightarrow$ & 337 | \makecell[c]{1/4 \\ 1/4 \\ 1/4 \\ 1/4} & 338 | \makecell[l]{forest \\ extremeHills \\ taiga \\ plains} \\\hline 339 | 340 | Cold, special & $\longrightarrow$ & 341 | \makecell[c]{1/1} & 342 | megaTaiga \\\hline 343 | 344 | Freezing& $\longrightarrow$ & 345 | \makecell[c]{3/4 \\ 1/4} & 346 | \makecell[l]{icePlains \\ coldTaiga} 347 | 348 | \end{tabular} 349 | 350 | \medskip\noindent 351 | Ocean and Mushroom types are not affected by this layer. The special category is selected when one of the higher bits (0xF00) are set. E.g. 0x603 has high bits and is thus a special Cold(3) category. 352 | 353 | 354 | \subsection{Layer 20: Zoom} 355 | \begin{tabular}{|l|l|l|}\hline 356 | Scale: & \multicolumn{2}{|l|}{1:128} \\\hline\hline 357 | Value & Type & Occurrence \\\hline 358 | 0 & ocean & 23.6\%\\\hline 359 | 1 & plains & 11.3\%\\\hline 360 | 2 & desert & 6.48\%\\\hline 361 | 3 & extremeHills & 9.28\%\\\hline 362 | 4 & forest & 9.28\%\\\hline 363 | 5 & taiga & 5.52\%\\\hline 364 | 6 & swampland & 3.61\%\\\hline 365 | 12 & icePlains & 4.94\%\\\hline 366 | 14 & mushroomIsland & 0.0586\%\\\hline 367 | 21 & jungle & 1.62\%\\\hline 368 | 24 & deepOcean & 9.09\%\\\hline 369 | 27 & birchForest & 3.61\%\\\hline 370 | 29 & roofedForest & 3.61\%\\\hline 371 | 30 & coldTaiga & 1.45\%\\\hline 372 | 32 & megaTaiga & 1.62\%\\\hline 373 | 35 & savanna & 4.12\%\\\hline 374 | 38 & mesaPlateau\_F & 0.602\%\\\hline 375 | 39 & mesaPlateau & 0.279\%\\\hline 376 | \end{tabular} 377 | 378 | 379 | \subsection{Layer 21: Zoom} 380 | \begin{tabular}{|l|l|l|}\hline 381 | Scale: & \multicolumn{2}{|l|}{1:64} \\\hline\hline 382 | Value & Type & Occurrence \\\hline 383 | 0 & ocean & 23.9\%\\\hline 384 | 1 & plains & 11.2\%\\\hline 385 | 2 & desert & 6.50\%\\\hline 386 | 3 & extremeHills & 9.23\%\\\hline 387 | 4 & forest & 9.23\%\\\hline 388 | 5 & taiga & 5.49\%\\\hline 389 | 6 & swampland & 3.56\%\\\hline 390 | 12 & icePlains & 5.00\%\\\hline 391 | 14 & mushroomIsland & 0.0543\%\\\hline 392 | 21 & jungle & 1.62\%\\\hline 393 | 24 & deepOcean & 9.03\%\\\hline 394 | 27 & birchForest & 3.58\%\\\hline 395 | 29 & roofedForest & 3.57\%\\\hline 396 | 30 & coldTaiga & 1.43\%\\\hline 397 | 32 & megaTaiga & 1.62\%\\\hline 398 | 35 & savanna & 4.08\%\\\hline 399 | 38 & mesaPlateau\_F & 0.603\%\\\hline 400 | 39 & mesaPlateau & 0.275\%\\\hline 401 | \end{tabular} 402 | \subsection{Layer 22: Biome Edge} 403 | \begin{tabular}{|l|l|l|}\hline 404 | Scale: & \multicolumn{2}{|l|}{1:64} \\\hline\hline 405 | Value & Type & Occurrence \\\hline 406 | 0 & ocean & 23.9\%\\\hline 407 | 1 & plains & 11.2\%\\\hline 408 | 2 & desert & 6.48\%\\\hline 409 | 3 & extremeHills & 9.23\%\\\hline 410 | 4 & forest & 9.23\%\\\hline 411 | 5 & taiga & 6.01\%\\\hline 412 | 6 & swampland & 3.47\%\\\hline 413 | 12 & icePlains & 5.00\%\\\hline 414 | 14 & mushroomIsland & 0.0543\%\\\hline 415 | 21 & jungle & 1.62\%\\\hline 416 | 23 & jungleEdge & 0.0144\%\\\hline 417 | 24 & deepOcean & 9.03\%\\\hline 418 | 27 & birchForest & 3.58\%\\\hline 419 | 29 & roofedForest & 3.57\%\\\hline 420 | 30 & coldTaiga & 1.43\%\\\hline 421 | 32 & megaTaiga & 1.11\%\\\hline 422 | 34 & extremeHillsPlus & 0.0111\%\\\hline 423 | 35 & savanna & 4.09\%\\\hline 424 | 37 & mesa & 0.321\%\\\hline 425 | 38 & mesaPlateau\_F & 0.385\%\\\hline 426 | 39 & mesaPlateau & 0.172\%\\\hline 427 | \end{tabular} 428 | 429 | \medskip\noindent 430 | Introduces the biomes jungleEdge, extremeHillsPlus and mesa. The conditional biome changes that take place in this layer are: 431 | 432 | \begin{tabular}{l c l} 433 | mesaPlateau\_F & $\longrightarrow$ & mesa\\ 434 | mesaPlateau & $\longrightarrow$ & mesa\\ 435 | megaTaiga & $\longrightarrow$ & taiga\\ 436 | desert & $\longrightarrow$ & extremeHillsPlus\\ 437 | swampland & $\longrightarrow$ & jungleEdge \\ 438 | swampland & $\longrightarrow$ & plains 439 | \end{tabular} 440 | 441 | \subsection{Layer 23: River Init} 442 | 443 | Starts a new branch of off Layer 18: Deep Ocean. This layer overwrites each map entry that is not Ocean(0) with a pseudo random number between 2 and 300000 (inclusive). 444 | 445 | \subsection{Layer 24: Zoom} 446 | \subsection{Layer 25: Zoom} 447 | 448 | \subsection{Layer 26: Hills} 449 | This is a multilayer which joins the biome generation with the river generator branch at the layers Biome Edge (22) and Zoom (25). However at this stage the river branch is mostly just used as a pseudo random number source. 450 | 451 | \medskip\noindent 452 | \begin{tabular}{|l|l|l|}\hline 453 | Scale: & \multicolumn{2}{|l|}{1:64} \\\hline\hline 454 | Value & Type & Occurrence \\\hline 455 | 0 & ocean & 17.5\%\\\hline 456 | 1 & plains & 9.86\%\\\hline 457 | 2 & desert & 4.83\%\\\hline 458 | 3 & extremeHills & 6.95\%\\\hline 459 | 4 & forest & 8.87\%\\\hline 460 | 5 & taiga & 4.67\%\\\hline 461 | 6 & swampland & 3.36\%\\\hline 462 | 12 & icePlains & 3.54\%\\\hline 463 | 13 & iceMountains & 1.30\%\\\hline 464 | 14 & mushroomIsland & 0.0543\%\\\hline 465 | 17 & desertHills & 1.46\%\\\hline 466 | 18 & forestHills & 2.68\%\\\hline 467 | 19 & taigaHills & 1.15\%\\\hline 468 | 21 & jungle & 1.15\%\\\hline 469 | 22 & jungleHills & 0.420\%\\\hline 470 | 23 & jungleEdge & 0.0140\%\\\hline 471 | 24 & deepOcean & 14.4\%\\\hline 472 | 27 & birchForest & 2.58\%\\\hline 473 | 28 & birchForestHills & 0.800\%\\\hline 474 | 29 & roofedForest & 2.57\%\\\hline 475 | 30 & coldTaiga & 1.11\%\\\hline 476 | 31 & coldTaigaHills & 0.282\%\\\hline 477 | 32 & megaTaiga & 0.688\%\\\hline 478 | 33 & megaTaigaHills & 0.344\%\\\hline 479 | 34 & extremeHillsPlus & 1.80\%\\\hline 480 | 35 & savanna & 3.05\%\\\hline 481 | 36 & savannaPlateau & 0.830\%\\\hline 482 | 37 & mesa & 0.486\%\\\hline 483 | 38 & mesaPlateau\_F & 0.240\%\\\hline 484 | 39 & mesaPlateau & 0.107\%\\\hline 485 | \end{tabular} 486 | \newpage\noindent 487 | \begin{tabular}{|l|l|l|}\hline 488 | 129 & Sunflower Plains & 0.4816\%\\\hline 489 | 130 & Desert M & 0.1971\%\\\hline 490 | 131 & Extreme Hills M & 0.2944\%\\\hline 491 | 132 & Flower Forest & 0.4904\%\\\hline 492 | 133 & Taiga M & 0.1897\%\\\hline 493 | 134 & Swampland M & 0.1109\%\\\hline 494 | 140 & Ice Plains Spikes & 0.1606\%\\\hline 495 | 149 & Jungle M & 0.0511\%\\\hline 496 | 151 & Jungle Edge M & 0.0005\%\\\hline 497 | 155 & Birch Forest M & 0.1154\%\\\hline 498 | 156 & Birch Forest Hills M & 0.0854\%\\\hline 499 | 157 & Roofed Forest M & 0.1144\%\\\hline 500 | 158 & Cold Taiga M & 0.0461\%\\\hline 501 | 160 & Mega Spruce Taiga & 0.0365\%\\\hline 502 | 161 & Redwood Taiga Hills & 0.0366\%\\\hline 503 | 162 & Extreme Hills+ M & 0.1913\%\\\hline 504 | 163 & Savanna M & 0.1240\%\\\hline 505 | 164 & Savanna Plateau M & 0.0853\%\\\hline 506 | 165 & Mesa (Bryce) & 0.0263\%\\\hline 507 | 166 & Mesa Plateau F M & 0.0123\%\\\hline 508 | 167 & Mesa Plateau M & 0.0056\%\\\hline 509 | \end{tabular} 510 | 511 | \medskip\noindent 512 | Nine new biomes: iceMountains, desertHills, forestHills, taigaHills, jungleHills, birchForestHills, coldTaigaHills, megaTaigaHills and savannaPlateau. Also there are 21 new mutated variants which I have listed by their ingame display name. 513 | 514 | This layer converts some map entries to related biomes, forming small biome patches. A list of the conversions that take place in this manor is shown below. Additionally, this layer adds 128 to some map entries, provided that the resulting biome ID is valid, forming mutated biome variants. 515 | 516 | \begin{tabular}{l c l} 517 | desert & $\longrightarrow$ & desertHill\\ 518 | forest & $\longrightarrow$ & forestHills\\ 519 | birchForest & $\longrightarrow$ & birchForestHills\\ 520 | roofedForest & $\longrightarrow$ & plains\\ 521 | taiga & $\longrightarrow$ & taigaHills\\ 522 | megaTaiga & $\longrightarrow$ & megaTaigaHills\\ 523 | coldTaiga & $\longrightarrow$ & coldTaigaHills\\ 524 | plains & $\longrightarrow$ & (1/3) forestHills, (2/3) forest\\ 525 | icePlains & $\longrightarrow$ & iceMountains\\ 526 | jungle & $\longrightarrow$ & jungleHills\\ 527 | ocean & $\longrightarrow$ & deepOcean\\ 528 | extremeHills & $\longrightarrow$ & extremeHillsPlus\\ 529 | savanna & $\longrightarrow$ & savannaPlateau\\ 530 | mesaPlateau\_F & $\longrightarrow$ & mesa\\ 531 | deepOcean & $\longrightarrow$ & (1/2) plains, (1/2) forest 532 | \end{tabular} 533 | 534 | \subsection{Layer 27: Rare Biome} 535 | \begin{tabular}{|l|l|l|}\hline 536 | Scale: & \multicolumn{2}{|l|}{1:64} \\\hline\hline 537 | Value & Type & Occurrence \\\hline 538 | 1 & plains & 9.68\%\\\hline 539 | 129 & Sunflower Plains & 0.654\%\\\hline 540 | ... & ... & ...\\\hline 541 | \end{tabular} 542 | 543 | \medskip\noindent 544 | This layer converts 1/57 th of Plains to Sunflower Plains. It has no affect on other biomes. 545 | 546 | \subsection{Layer 31: Shore} 547 | \begin{tabular}{|l|l|l|}\hline 548 | Scale: & \multicolumn{2}{|l|}{1:16} \\\hline\hline 549 | Value & Type & Occurrence \\\hline 550 | 0 & ocean & 15.7\%\\\hline 551 | 1 & plains & 8.93\%\\\hline 552 | 2 & desert & 4.59\%\\\hline 553 | 3 & extremeHills & 6.68\%\\\hline 554 | 4 & forest & 8.67\%\\\hline 555 | 5 & taiga & 4.39\%\\\hline 556 | 6 & swampland & 3.44\%\\\hline 557 | 12 & icePlains & 3.44\%\\\hline 558 | 13 & iceMountains & 1.15\%\\\hline 559 | 14 & mushroomIsland & 0.0370\%\\\hline 560 | 15 & mushroomIslandShore & 0.0208\%\\\hline 561 | 16 & beach & 3.81\%\\\hline 562 | 17 & desertHills & 1.27\%\\\hline 563 | 18 & forestHills & 2.27\%\\\hline 564 | 19 & taigaHills & 0.975\%\\\hline 565 | 21 & jungle & 1.03\%\\\hline 566 | 22 & jungleHills & 0.359\%\\\hline 567 | 23 & jungleEdge & 0.0853\%\\\hline 568 | 24 & deepOcean & 15.7\%\\\hline 569 | 25 & stoneBeach & 0.534\%\\\hline 570 | 26 & coldBeach & 0.311\%\\\hline 571 | 27 & birchForest & 2.45\%\\\hline 572 | 28 & birchForestHills & 0.800\%\\\hline 573 | 29 & roofedForest & 2.57\%\\\hline 574 | 30 & coldTaiga & 1.07\%\\\hline 575 | 31 & coldTaigaHills & 0.246\%\\\hline 576 | 32 & megaTaiga & 0.691\%\\\hline 577 | 33 & megaTaigaHills & 0.313\%\\\hline 578 | 34 & extremeHillsPlus & 2.84\%\\\hline 579 | 35 & savanna & 3.05\%\\\hline 580 | 36 & savannaPlateau & 0.715\%\\\hline 581 | 37 & mesa & 0.469\%\\\hline 582 | 38 & mesaPlateau\_F & 0.242\%\\\hline 583 | 39 & mesaPlateau & 0.103\%\\\hline 584 | \end{tabular} 585 | \newpage\noindent 586 | \begin{tabular}{|l|l|l|}\hline 587 | 129 & Sunflower Plains & 0.571\%\\\hline 588 | 130 & Desert M & 0.188\%\\\hline 589 | 131 & Extreme Hills M & 0.284\%\\\hline 590 | 132 & Flower Forest & 0.430\%\\\hline 591 | 133 & Taiga M & 0.176\%\\\hline 592 | 134 & Swampland M & 0.111\%\\\hline 593 | 140 & Ice Plains Spikes & 0.157\%\\\hline 594 | 149 & Jungle M & 0.0492\%\\\hline 595 | 151 & Jungle Edge M & 0.000451\%\\\hline 596 | 155 & Birch Forest M & 0.109\%\\\hline 597 | 156 & Birch Forest Hills M & 0.0827\%\\\hline 598 | 157 & Roofed Forest M & 0.114\%\\\hline 599 | 158 & Cold Taiga M & 0.0477\%\\\hline 600 | 160 & Mega Spruce Taiga & 0.0358\%\\\hline 601 | 161 & Redwood Taiga Hills & 0.0354\%\\\hline 602 | 162 & Extreme Hills+ M & 0.184\%\\\hline 603 | 163 & Savanna M & 0.119\%\\\hline 604 | 164 & Savanna Plateau M & 0.0824\%\\\hline 605 | 165 & Mesa (Bryce) & 0.0236\%\\\hline 606 | 166 & Mesa Plateau F M & 0.0121\%\\\hline 607 | 167 & Mesa Plateau M & 0.00566\%\\\hline 608 | \end{tabular} 609 | 610 | \medskip\noindent 611 | New biomes: mushroomIslandShore, beach, stoneBeach, coldBeach. 612 | 613 | \subsection{Layer 41: River} 614 | \begin{tabular}{|l|l|l|}\hline 615 | Scale: & \multicolumn{2}{|l|}{1:4} \\\hline\hline 616 | Value & Type & Occurrence \\\hline 617 | -1 & none & 94.3\%\\\hline 618 | 7 & river & 5.70\%\\\hline 619 | \end{tabular} 620 | 621 | \medskip\noindent 622 | Uses the zoomed pseudo random output of the river branch to determine the position of rivers in the world. All other values are set to -1. 623 | 624 | \subsection{Layer 43: River Mix} 625 | \begin{tabular}{|l|l|l|}\hline 626 | Scale: & \multicolumn{2}{|l|}{1:4} \\\hline\hline 627 | Value & Type & Occurrence \\\hline 628 | 0 & ocean & 13.9\%\\\hline 629 | 1 & plains & 9.69\%\\\hline 630 | 2 & desert & 4.80\%\\\hline 631 | 3 & extremeHills & 7.24\%\\\hline 632 | 4 & forest & 9.21\%\\\hline 633 | 5 & taiga & 4.47\%\\\hline 634 | 6 & swampland & 4.03\%\\\hline 635 | 7 & river & 4.19\%\\\hline 636 | 11 & frozenRiver & 0.0872\%\\\hline 637 | 12 & icePlains & 1.52\%\\\hline 638 | 13 & iceMountains & 0.495\%\\\hline 639 | 14 & mushroomIsland & 0.0257\%\\\hline 640 | 15 & mushroomIslandShore & 0.0172\%\\\hline 641 | 16 & beach & 2.96\%\\\hline 642 | 17 & desertHills & 1.33\%\\\hline 643 | 18 & forestHills & 2.50\%\\\hline 644 | 19 & taigaHills & 0.994\%\\\hline 645 | 21 & jungle & 1.21\%\\\hline 646 | 22 & jungleHills & 0.421\%\\\hline 647 | 23 & jungleEdge & 0.101\%\\\hline 648 | 24 & deepOcean & 12.7\%\\\hline 649 | 25 & stoneBeach & 0.426\%\\\hline 650 | 26 & coldBeach & 0.132\%\\\hline 651 | 27 & birchForest & 2.96\%\\\hline 652 | 28 & birchForestHills & 0.849\%\\\hline 653 | 29 & roofedForest & 2.93\%\\\hline 654 | 30 & coldTaiga & 0.466\%\\\hline 655 | 31 & coldTaigaHills & 0.107\%\\\hline 656 | 32 & megaTaiga & 0.704\%\\\hline 657 | 33 & megaTaigaHills & 0.316\%\\\hline 658 | 34 & extremeHillsPlus & 1.69\%\\\hline 659 | 35 & savanna & 2.97\%\\\hline 660 | 36 & savannaPlateau & 0.750\%\\\hline 661 | 37 & mesa & 0.456\%\\\hline 662 | 38 & mesaPlateau\_F & 0.251\%\\\hline 663 | 39 & mesaPlateau & 0.110\%\\\hline 664 | \end{tabular} 665 | \newpage\noindent 666 | \begin{tabular}{|l|l|l|}\hline 667 | 129 & Sunflower Plains & 0.616\%\\\hline 668 | 130 & Desert M & 0.205\%\\\hline 669 | 131 & Extreme Hills M & 0.315\%\\\hline 670 | 132 & Flower Forest & 0.477\%\\\hline 671 | 133 & Taiga M & 0.184\%\\\hline 672 | 134 & Swampland M & 0.130\%\\\hline 673 | 140 & Ice Plains Spikes & 0.0681\%\\\hline 674 | 149 & Jungle M & 0.0582\%\\\hline 675 | 151 & Jungle Edge M & 0.000625\%\\\hline 676 | 155 & Birch Forest M & 0.136\%\\\hline 677 | 156 & Birch Forest Hills M & 0.101\%\\\hline 678 | 157 & Roofed Forest M & 0.136\%\\\hline 679 | 158 & Cold Taiga M & 0.0196\%\\\hline 680 | 160 & Mega Spruce Taiga & 0.0371\%\\\hline 681 | 161 & Redwood Taiga Hills & 0.0369\%\\\hline 682 | 162 & Extreme Hills+ M & 0.203\%\\\hline 683 | 163 & Savanna M & 0.128\%\\\hline 684 | 164 & Savanna Plateau M & 0.0882\%\\\hline 685 | 165 & Mesa (Bryce) & 0.0257\%\\\hline 686 | 166 & Mesa Plateau F M & 0.0134\%\\\hline 687 | 167 & Mesa Plateau M & 0.00585\%\\\hline 688 | \end{tabular} 689 | 690 | \medskip\noindent 691 | This layer is actually used in parts of the Minecraft code where a faster alternative for the full biome generator is required. Note that this layer has a scale of 1:4 and the final map is just a zoomed version of this layer's output. The function of this layer is to apply the rivers to the main biome branch. A new biome is also added in this layer: frozenRiver. 692 | 693 | 694 | \subsection{Layer 44: Voronoi Zoom} 695 | \begin{tabular}{|l|l|l|}\hline 696 | Scale: & \multicolumn{2}{|l|}{1:1} \\\hline\hline 697 | Value & Type & Occurrence \\\hline 698 | 0 & ocean & 13.7\%\\\hline 699 | 1 & plains & 10.0\%\\\hline 700 | 2 & desert & 4.84\%\\\hline 701 | 3 & extremeHills & 7.50\%\\\hline 702 | 4 & forest & 9.54\%\\\hline 703 | 5 & taiga & 4.59\%\\\hline 704 | 6 & swampland & 4.22\%\\\hline 705 | 7 & river & 4.30\%\\\hline 706 | 11 & frozenRiver & 0.0806\%\\\hline 707 | 12 & icePlains & 1.40\%\\\hline 708 | 13 & iceMountains & 0.451\%\\\hline 709 | 14 & mushroomIsland & 0.0209\%\\\hline 710 | 15 & mushroomIslandShore & 0.0137\%\\\hline 711 | 16 & beach & 2.92\%\\\hline 712 | 17 & desertHills & 1.33\%\\\hline 713 | 18 & forestHills & 2.59\%\\\hline 714 | 19 & taigaHills & 1.00\%\\\hline 715 | 21 & jungle & 1.26\%\\\hline 716 | 22 & jungleHills & 0.429\%\\\hline 717 | 23 & jungleEdge & 0.118\%\\\hline 718 | 24 & deepOcean & 11.2\%\\\hline 719 | 25 & stoneBeach & 0.433\%\\\hline 720 | 26 & coldBeach & 0.118\%\\\hline 721 | 27 & birchForest & 3.12\%\\\hline 722 | 28 & birchForestHills & 0.890\%\\\hline 723 | 29 & roofedForest & 3.09\%\\\hline 724 | 30 & coldTaiga & 0.428\%\\\hline 725 | 31 & coldTaigaHills & 0.0984\%\\\hline 726 | 32 & megaTaiga & 0.675\%\\\hline 727 | 33 & megaTaigaHills & 0.303\%\\\hline 728 | 34 & extremeHillsPlus & 1.74\%\\\hline 729 | 35 & savanna & 3.00\%\\\hline 730 | 36 & savannaPlateau & 0.751\%\\\hline 731 | 37 & mesa & 0.464\%\\\hline 732 | 38 & mesaPlateau\_F & 0.238\%\\\hline 733 | 39 & mesaPlateau & 0.105\%\\\hline 734 | \end{tabular} 735 | \newpage\noindent 736 | \begin{tabular}{|l|l|l|}\hline 737 | 129 & Sunflower Plains & 0.635\%\\\hline 738 | 130 & Desert M & 0.203\%\\\hline 739 | 131 & Extreme Hills M & 0.325\%\\\hline 740 | 132 & Flower Forest & 0.491\%\\\hline 741 | 133 & Taiga M & 0.190\%\\\hline 742 | 134 & Swampland M & 0.134\%\\\hline 743 | 140 & Ice Plains Spikes & 0.0625\%\\\hline 744 | 149 & Jungle M & 0.0612\%\\\hline 745 | 151 & Jungle Edge M & 0.000781\%\\\hline 746 | 155 & Birch Forest M & 0.144\%\\\hline 747 | 156 & Birch Forest Hills M & 0.106\%\\\hline 748 | 157 & Roofed Forest M & 0.142\%\\\hline 749 | 158 & Cold Taiga M & 0.0181\%\\\hline 750 | 160 & Mega Spruce Taiga & 0.0356\%\\\hline 751 | 161 & Redwood Taiga Hills & 0.0354\%\\\hline 752 | 162 & Extreme Hills+ M & 0.210\%\\\hline 753 | 163 & Savanna M & 0.129\%\\\hline 754 | 164 & Savanna Plateau M & 0.0885\%\\\hline 755 | 165 & Mesa (Bryce) & 0.0258\%\\\hline 756 | 166 & Mesa Plateau F M & 0.0131\%\\\hline 757 | 167 & Mesa Plateau M & 0.00559\%\\\hline 758 | \end{tabular} 759 | 760 | \medskip\noindent 761 | This is the final layer in the biome generator and contains all the Overworld biomes except for frozenOcean, which does not generate in Mincraft 1.7 - 1.12. 762 | 763 | \end{document} 764 | 765 | 766 | 767 | -------------------------------------------------------------------------------- /backup/cubiomes/docs/layers.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedrock-dev/MCBEStructureFinder/14d79b8c92f6d67d1e4556e535b8babef3cc91b9/backup/cubiomes/docs/layers.odg -------------------------------------------------------------------------------- /backup/cubiomes/docs/layers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedrock-dev/MCBEStructureFinder/14d79b8c92f6d67d1e4556e535b8babef3cc91b9/backup/cubiomes/docs/layers.pdf -------------------------------------------------------------------------------- /backup/cubiomes/generator.c: -------------------------------------------------------------------------------- 1 | #include "generator.h" 2 | #include "layers.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | Layer *setupLayer(LayerStack *g, int layerId, mapfunc_t *map, int mc, 10 | int8_t zoom, int8_t edge, uint64_t saltbase, Layer *p, Layer *p2) { 11 | Layer *l = g->layers + layerId; 12 | l->getMap = map; 13 | l->mc = mc; 14 | l->zoom = zoom; 15 | l->edge = edge; 16 | l->scale = 0; 17 | if (saltbase == 0) 18 | l->layerSalt = saltbase; 19 | else 20 | l->layerSalt = getLayerSalt(saltbase); 21 | l->startSalt = 0; 22 | l->startSeed = 0; 23 | l->data = NULL; 24 | l->p = p; 25 | l->p2 = p2; 26 | return l; 27 | } 28 | 29 | static void setupScale(Layer *l, int scale) { 30 | l->scale = scale; 31 | if (l->p) 32 | setupScale(l->p, scale * l->zoom); 33 | if (l->p2) 34 | setupScale(l->p2, scale * l->zoom); 35 | } 36 | 37 | void setupOverworldGenerator(LayerStack *g, int mc) { 38 | memset(g, 0, sizeof(LayerStack)); 39 | Layer *p; 40 | 41 | // G: generator layer stack 42 | // L: layer ID 43 | // M: mapping function 44 | // V: minecraft version 45 | // Z: zoom 46 | // E: edge 47 | // S: salt base 48 | // P1: parent 1 49 | // P2: parent 2 50 | 51 | // G, L, M V Z E S P1 P2 52 | p = setupLayer(g, L_CONTINENT_4096, mapContinent, mc, 1, 0, 1, 0, 0); //1 53 | p = setupLayer(g, L_ZOOM_2048, mapZoomFuzzy, mc, 2, 3, 2000, p, 0); //2 54 | p = setupLayer(g, L_LAND_2048, mapLand, mc, 1, 2, 1, p, 0); //3 55 | p = setupLayer(g, L_ZOOM_1024, mapZoom, mc, 2, 3, 2001, p, 0);//4 56 | p = setupLayer(g, L_LAND_1024_A, mapLand, mc, 1, 2, 2, p, 0);//5 57 | 58 | // G L M V Z E S P1 P2 59 | p = setupLayer(g, L_LAND_1024_B, mapLand, mc, 1, 2, 50, p, 0); //6 60 | p = setupLayer(g, L_LAND_1024_C, mapLand, mc, 1, 2, 70, p, 0);//7 61 | p = setupLayer(g, L_ISLAND_1024, mapIsland, mc, 1, 2, 2, p, 0);//8 62 | p = setupLayer(g, L_SNOW_1024, mapSnow, mc, 1, 2, 2, p, 0); 63 | p = setupLayer(g, L_LAND_1024_D, mapLand, mc, 1, 2, 3, p, 0); 64 | 65 | 66 | p = setupLayer(g, L_COOL_1024, mapCool, mc, 1, 2, 2, p, 0); 67 | p = setupLayer(g, L_HEAT_1024, mapHeat, mc, 1, 2, 2, p, 0); 68 | p = setupLayer(g, L_SPECIAL_1024, mapSpecial, mc, 1, 2, 3, p, 0); 69 | p = setupLayer(g, L_ZOOM_512, mapZoom, mc, 2, 3, 2002, p, 0); 70 | p = setupLayer(g, L_ZOOM_256, mapZoom, mc, 2, 3, 2003, p, 0); 71 | 72 | 73 | p = setupLayer(g, L_LAND_256, mapLand, mc, 1, 2, 4, p, 0); 74 | p = setupLayer(g, L_BIOME_256, mapBiome, mc, 1, 0, 200, p, 0); 75 | p = setupLayer(g, L_MUSHROOM_256, mapMushroom, mc, 1, 2, 5, p, 0); 76 | p = setupLayer(g, L_DEEP_OCEAN_256, mapDeepOcean, mc, 1, 2, 4, p, 0); 77 | 78 | 79 | //19-- 80 | p = setupLayer(g, L_BAMBOO_256, mapBamboo, mc, 1, 0, 1001, p, 0); 81 | p = setupLayer(g, L_ZOOM_128, mapZoom, mc, 2, 3, 1001, p, 0); 82 | p = setupLayer(g, L_ZOOM_64, mapZoom, mc, 2, 3, 1001, p, 0); 83 | p = setupLayer(g, L_BIOME_EDGE_64, mapBiomeEdge, mc, 1, 2, 1000, p, 0); 84 | // river noise layer chain, also used to determine where hills generate 85 | p = setupLayer(g, L_RIVER_INIT_256, mapNoise, mc, 1, 0, 100, 86 | g->layers + L_DEEP_OCEAN_256, 0); 87 | p = setupLayer(g, L_ZOOM_128_HILLS, mapZoom, mc, 2, 3, 0, p, 0); 88 | p = setupLayer(g, L_ZOOM_64_HILLS, mapZoom, mc, 2, 3, 0, p, 0); 89 | 90 | p = setupLayer(g, L_HILLS_64, mapHills, mc, 1, 2, 1000, 91 | g->layers + L_BIOME_EDGE_64, g->layers + L_ZOOM_64_HILLS); 92 | 93 | p = setupLayer(g, L_SUNFLOWER_64, mapSunflower, mc, 1, 0, 1001, p, 0); 94 | p = setupLayer(g, L_ZOOM_32, mapZoom, mc, 2, 3, 1000, p, 0); 95 | p = setupLayer(g, L_LAND_32, mapLand, mc, 1, 2, 3, p, 0); 96 | p = setupLayer(g, L_ZOOM_16, mapZoom, mc, 2, 3, 1001, p, 0); 97 | p = setupLayer(g, L_SHORE_16, mapShore, mc, 1, 2, 1000, p, 0); 98 | p = setupLayer(g, L_ZOOM_8, mapZoom, mc, 2, 3, 1002, p, 0); 99 | p = setupLayer(g, L_ZOOM_4, mapZoom, mc, 2, 3, 1003, p, 0); 100 | 101 | p = setupLayer(g, L_SMOOTH_4, mapSmooth, mc, 1, 2, 1000, p, 0); 102 | 103 | // river layer chain 104 | p = setupLayer(g, L_ZOOM_128_RIVER, mapZoom, mc, 2, 3, 1001, 105 | g->layers + L_RIVER_INIT_256, 0); 106 | 107 | p = setupLayer(g, L_ZOOM_64_RIVER, mapZoom, mc, 2, 3, 1001, p, 0); 108 | p = setupLayer(g, L_ZOOM_32_RIVER, mapZoom, mc, 2, 3, 1001, p, 0); 109 | p = setupLayer(g, L_ZOOM_16_RIVER, mapZoom, mc, 2, 3, 1001, p, 0); 110 | p = setupLayer(g, L_ZOOM_8_RIVER, mapZoom, mc, 2, 3, 1001, p, 0); 111 | p = setupLayer(g, L_ZOOM_4_RIVER, mapZoom, mc, 2, 3, 1001, p, 0); 112 | 113 | p = setupLayer(g, L_RIVER_4, mapRiver, mc, 1, 2, 1, p, 0); 114 | p = setupLayer(g, L_SMOOTH_4_RIVER, mapSmooth, mc, 1, 2, 1000, p, 0); 115 | 116 | p = setupLayer(g, L_RIVER_MIX_4, mapRiverMix, mc, 1, 0, 100, 117 | g->layers + L_SMOOTH_4, g->layers + L_SMOOTH_4_RIVER); 118 | 119 | // ocean variants 120 | p = setupLayer(g, L_OCEAN_TEMP_256, mapOceanTemp, mc, 1, 0, 2, 0, 0); 121 | p = setupLayer(g, L_OCEAN_EDGE_256, mapOceanEdge, mc, 1, 2, 2, p, 0); 122 | p = setupLayer(g, L_ZOOM_128_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 123 | p = setupLayer(g, L_ZOOM_64_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 124 | p = setupLayer(g, L_ZOOM_32_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 125 | p = setupLayer(g, L_ZOOM_16_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 126 | p = setupLayer(g, L_ZOOM_8_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 127 | p = setupLayer(g, L_ZOOM_4_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0); 128 | p = setupLayer(g, L_OCEAN_MIX_4, mapOceanMix, mc, 1, 17, 100, 129 | g->layers + L_RIVER_MIX_4, g->layers + L_ZOOM_4_OCEAN); 130 | 131 | p = setupLayer(g, L_VORONOI_1, mapVoronoi, mc, 4, 7, 10, p, 0); 132 | 133 | g->entry_1 = p; 134 | g->entry_4 = g->layers + L_OCEAN_MIX_4; 135 | g->entry_16 = g->layers + L_SHORE_16; 136 | g->entry_64 = g->layers + L_SUNFLOWER_64; 137 | g->entry_256 = g->layers + L_BAMBOO_256; 138 | 139 | setupScale(g->entry_1, 1); 140 | } 141 | 142 | /* Recursively calculates the minimum buffer size required to generate an area 143 | * of the specified size from the current layer onwards. 144 | */ 145 | static void getMaxArea(const Layer *layer, int areaX, int areaZ, int *maxX, int *maxZ) { 146 | if (layer == NULL) 147 | return; 148 | 149 | if (layer->zoom == 2) { 150 | areaX >>= 1; 151 | areaZ >>= 1; 152 | } else if (layer->zoom == 4) { 153 | areaX >>= 2; 154 | areaZ >>= 2; 155 | } 156 | 157 | areaX += layer->edge; 158 | areaZ += layer->edge; 159 | 160 | if (areaX > *maxX) *maxX = areaX; 161 | if (areaZ > *maxZ) *maxZ = areaZ; 162 | 163 | getMaxArea(layer->p, areaX, areaZ, maxX, maxZ); 164 | getMaxArea(layer->p2, areaX, areaZ, maxX, maxZ); 165 | } 166 | 167 | int calcRequiredBuf(const Layer *layer, int areaX, int areaZ) { 168 | int maxX = areaX, maxZ = areaZ; 169 | getMaxArea(layer, areaX, areaZ, &maxX, &maxZ); 170 | 171 | return maxX * maxZ; 172 | } 173 | 174 | int *allocCache(const Layer *layer, int sizeX, int sizeZ) { 175 | int size = calcRequiredBuf(layer, sizeX, sizeZ); 176 | 177 | int *ret = (int *) malloc(sizeof(*ret) * size); 178 | memset(ret, 0, sizeof(*ret) * size); 179 | 180 | return ret; 181 | } 182 | 183 | 184 | void applySeed(LayerStack *g, uint64_t seed) { 185 | // the seed has to be applied recursively 186 | setLayerSeed(g->entry_1, seed); 187 | } 188 | 189 | int genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight) { 190 | memset(out, 0, areaWidth * areaHeight * sizeof(*out)); 191 | return layer->getMap(layer, out, areaX, areaZ, areaWidth, areaHeight); 192 | } 193 | 194 | int genNetherScaled(int mc, uint64_t seed, int scale, int *out, 195 | int x, int z, int w, int h, int y0, int y1) { 196 | if (scale != 1 && scale != 4 && scale != 16 && scale != 64) 197 | return 1; // unsupported scale 198 | 199 | NetherNoise nn; 200 | setNetherSeed(&nn, seed); 201 | 202 | if (scale == 1) { 203 | if (y0 != 0 || y1 != 0) { 204 | printf("getNetherScaled(): volume voronoi not implemented yet\n"); 205 | return 1; 206 | } 207 | 208 | int vx = x - 2; 209 | int vz = z - 2; 210 | int pX = vx >> 2; 211 | int pZ = vz >> 2; 212 | int pW = ((vx + w) >> 2) - pX + 2; 213 | int pH = ((vz + h) >> 2) - pZ + 2; 214 | 215 | int err = mapNether2D(&nn, out, pX, pZ, pW, pH); 216 | if (err) 217 | return err; 218 | Layer lvoronoi; 219 | memset(&lvoronoi, 0, sizeof(Layer)); 220 | lvoronoi.layerSalt = getLayerSalt(10); 221 | setLayerSeed(&lvoronoi, seed); 222 | return mapVoronoi(&lvoronoi, out, x, z, w, h); 223 | } else { 224 | return mapNether3D(&nn, out, x, z, w, h, y0, y1 - y0 + 1, scale, 1.0); 225 | } 226 | } 227 | 228 | 229 | int genEndScaled(int mc, uint64_t seed, int scale, int *out, 230 | int x, int z, int w, int h) { 231 | if (scale != 1) 232 | return 1; // unsupported scale 233 | 234 | int i, siz = w * h; 235 | for (i = 0; i < siz; i++) 236 | out[i] = the_end; 237 | return 0; 238 | } 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /backup/cubiomes/generator.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERATOR_H_ 2 | #define GENERATOR_H_ 3 | 4 | #include "layers.h" 5 | 6 | 7 | /* Enumeration of the layer indices in the generator. */ 8 | enum 9 | { 10 | // new [[deprecated]] 11 | L_CONTINENT_4096 = 0, L_ISLAND_4096 = L_CONTINENT_4096, 12 | L_ZOOM_2048, 13 | L_LAND_2048, L_ADD_ISLAND_2048 = L_LAND_2048, 14 | L_ZOOM_1024, 15 | L_LAND_1024_A, L_ADD_ISLAND_1024A = L_LAND_1024_A, 16 | L_LAND_1024_B, L_ADD_ISLAND_1024B = L_LAND_1024_B, // 1.7+ 17 | L_LAND_1024_C, L_ADD_ISLAND_1024C = L_LAND_1024_C, // 1.7+ 18 | L_ISLAND_1024, L_REMOVE_OCEAN_1024 = L_ISLAND_1024, // 1.7+ 19 | L_SNOW_1024, L_ADD_SNOW_1024 = L_SNOW_1024, 20 | L_LAND_1024_D, L_ADD_ISLAND_1024D = L_LAND_1024_D, // 1.7+ 21 | L_COOL_1024, L_COOL_WARM_1024 = L_COOL_1024, // 1.7+ 22 | L_HEAT_1024, L_HEAT_ICE_1024 = L_HEAT_1024, // 1.7+ 23 | L_SPECIAL_1024, // 1.7+ 24 | L_ZOOM_512, 25 | //L_LAND_512, // 1.6- 26 | L_ZOOM_256, 27 | L_LAND_256, L_ADD_ISLAND_256 = L_LAND_256, 28 | L_BIOME_256, 29 | L_MUSHROOM_256, L_ADD_MUSHROOM_256 = L_MUSHROOM_256, 30 | L_DEEP_OCEAN_256, // 1.7+ 31 | L_BAMBOO_256, L14_BAMBOO_256 = L_BAMBOO_256, // 1.14+ 32 | L_ZOOM_128, 33 | L_ZOOM_64, 34 | L_BIOME_EDGE_64, 35 | L_NOISE_256, L_RIVER_INIT_256 = L_NOISE_256, 36 | L_ZOOM_128_HILLS, 37 | L_ZOOM_64_HILLS, 38 | L_HILLS_64, 39 | L_SUNFLOWER_64, L_RARE_BIOME_64 = L_SUNFLOWER_64, // 1.7+ 40 | L_ZOOM_32, 41 | L_LAND_32, L_ADD_ISLAND_32 = L_LAND_32, 42 | L_ZOOM_16, 43 | L_SHORE_16, 44 | //L_SWAMP_RIVER_16, // 1.6- 45 | L_ZOOM_8, 46 | L_ZOOM_4, 47 | L_SMOOTH_4, 48 | L_ZOOM_128_RIVER, 49 | L_ZOOM_64_RIVER, 50 | L_ZOOM_32_RIVER, 51 | L_ZOOM_16_RIVER, 52 | L_ZOOM_8_RIVER, 53 | L_ZOOM_4_RIVER, 54 | L_RIVER_4, 55 | L_SMOOTH_4_RIVER, 56 | L_RIVER_MIX_4, 57 | L_OCEAN_TEMP_256, L13_OCEAN_TEMP_256 = L_OCEAN_TEMP_256, // 1.13+ 58 | L_OCEAN_EDGE_256, 59 | L_ZOOM_128_OCEAN, L13_ZOOM_128 = L_ZOOM_128_OCEAN, // 1.13+ 60 | L_ZOOM_64_OCEAN, L13_ZOOM_64 = L_ZOOM_64_OCEAN, // 1.13+ 61 | L_ZOOM_32_OCEAN, L13_ZOOM_32 = L_ZOOM_32_OCEAN, // 1.13+ 62 | L_ZOOM_16_OCEAN, L13_ZOOM_16 = L_ZOOM_16_OCEAN, // 1.13+ 63 | L_ZOOM_8_OCEAN, L13_ZOOM_8 = L_ZOOM_8_OCEAN, // 1.13+ 64 | L_ZOOM_4_OCEAN, L13_ZOOM_4 = L_ZOOM_4_OCEAN, // 1.13+ 65 | L_OCEAN_MIX_4, L13_OCEAN_MIX_4 = L_OCEAN_MIX_4, // 1.13+ 66 | L_VORONOI_1, L_VORONOI_ZOOM_1 = L_VORONOI_1, 67 | 68 | // // largeBiomes layers 69 | // L_ZOOM_LARGE_A, 70 | // L_ZOOM_LARGE_B, 71 | // L_ZOOM_L_RIVER_A, 72 | // L_ZOOM_L_RIVER_B, 73 | 74 | L_NUM 75 | }; 76 | 77 | 78 | STRUCT(LayerStack) 79 | { 80 | Layer layers[L_NUM]; 81 | Layer *entry_1; // entry scale (1:1) [L_VORONOI_1] 82 | Layer *entry_4; // entry scale (1:4) [L_RIVER_MIX_4|L_OCEAN_MIX_4] 83 | // unofficial entries for other scales (latest sensible layers): 84 | Layer *entry_16; // [L_SWAMP_RIVER_16|L_SHORE_16] 85 | Layer *entry_64; // [L_HILLS_64|L_SUNFLOWER_64] 86 | Layer *entry_256; // [L_BIOME_256|L_BAMBOO_256] 87 | }; 88 | 89 | 90 | #ifdef __cplusplus 91 | extern "C" 92 | { 93 | #endif 94 | 95 | /* Initialise an instance of a generator. */ 96 | void setupOverworldGenerator(LayerStack *g, int mc); 97 | 98 | /* Calculates the minimum size of the buffers required to generate an area of 99 | * dimensions 'sizeX' by 'sizeZ' at the specified layer. 100 | */ 101 | int calcRequiredBuf(const Layer *layer, int areaX, int areaZ); 102 | 103 | /* Allocates an amount of memory required to generate an area of dimensions 104 | * 'sizeX' by 'sizeZ' for the magnification of the given layer. 105 | */ 106 | int *allocCache(const Layer *layer, int sizeX, int sizeZ); 107 | 108 | 109 | /* Set up custom layers. */ 110 | Layer *setupLayer(LayerStack *g, int layerId, mapfunc_t *map, int mc, 111 | int8_t zoom, int8_t edge, uint64_t saltbase, Layer *p, Layer *p2); 112 | 113 | /* Sets the world seed for the generator */ 114 | void applySeed(LayerStack *g, uint64_t seed); 115 | 116 | /* Generates the specified area using the current generator settings and stores 117 | * the biomeIDs in 'out'. 118 | * The biomeIDs will be indexed in the form: out[x + z*areaWidth] 119 | * It is recommended that 'out' is allocated using allocCache() for the correct 120 | * buffer size. 121 | */ 122 | int genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight); 123 | 124 | 125 | /* Generate nether or end biomes at scales: 1:1, 1:4, 1:16, or 1:64 126 | * @mc minecaft version 127 | * @seed world seed 128 | * @scale mapping scale of output, has to be one of 1, 4, 16, or 64 129 | * @out output buffer, out[yi*w*h + zi*w + xi], size = w*h*(y1-y0+1) 130 | * for voronoi (scale=1) add 7 to each dimension as buffer 131 | * @x,z,w,h planar area 132 | * @y0,y1 min and max vertical dimensions (inclusive) 133 | * @return zero upon success 134 | */ 135 | int genNetherScaled(int mc, uint64_t seed, int scale, int *out, 136 | int x, int z, int w, int h, int y0, int y1); 137 | int genEndScaled(int mc, uint64_t seed, int scale, int *out, 138 | int x, int z, int w, int h); 139 | 140 | 141 | #ifdef __cplusplus 142 | } 143 | #endif 144 | 145 | #endif /* GENERATOR_H_ */ 146 | 147 | -------------------------------------------------------------------------------- /backup/cubiomes/javarnd.h: -------------------------------------------------------------------------------- 1 | #ifndef JAVARND_H_ 2 | #define JAVARND_H_ 3 | 4 | #include 5 | 6 | 7 | /********************** C copy of the Java Random methods ********************** 8 | */ 9 | 10 | static inline void setSeed(uint64_t *seed, uint64_t value) 11 | { 12 | *seed = (value ^ 0x5deece66d) & ((1ULL << 48) - 1); 13 | } 14 | 15 | static inline int next(uint64_t *seed, const int bits) 16 | { 17 | *seed = (*seed * 0x5deece66d + 0xb) & ((1ULL << 48) - 1); 18 | return (int) ((int64_t)*seed >> (48 - bits)); 19 | } 20 | 21 | static inline int nextInt(uint64_t *seed, const int n) 22 | { 23 | int bits, val; 24 | const int m = n - 1; 25 | 26 | if ((m & n) == 0) { 27 | uint64_t x = n * (uint64_t)next(seed, 31); 28 | return (int) ((int64_t) x >> 31); 29 | } 30 | 31 | do { 32 | bits = next(seed, 31); 33 | val = bits % n; 34 | } 35 | while (bits - val + m < 0); 36 | return val; 37 | } 38 | 39 | static inline uint64_t nextLong(uint64_t *seed) 40 | { 41 | return ((uint64_t) next(seed, 32) << 32) + next(seed, 32); 42 | } 43 | 44 | static inline float nextFloat(uint64_t *seed) 45 | { 46 | return next(seed, 24) / (float) (1 << 24); 47 | } 48 | 49 | static inline double nextDouble(uint64_t *seed) 50 | { 51 | uint64_t x = (uint64_t)next(seed, 26); 52 | x <<= 27; 53 | x += next(seed, 27); 54 | return (int64_t) x / (double) (1ULL << 53); 55 | } 56 | 57 | /* A macro to generate the ideal assembly for X = nextInt(S, 24) 58 | * This is a macro and not an inline function, as many compilers can make use 59 | * of the additional optimisation passes for the surrounding code. 60 | */ 61 | #define JAVA_NEXT_INT24(S,X) \ 62 | do { \ 63 | uint64_t a = (1ULL << 48) - 1; \ 64 | uint64_t c = 0x5deece66dULL * (S); \ 65 | c += 11; a &= c; \ 66 | (S) = a; \ 67 | a = (uint64_t) ((int64_t)a >> 17); \ 68 | c = 0xaaaaaaab * a; \ 69 | c = (uint64_t) ((int64_t)c >> 36); \ 70 | (X) = (int)a - (int)(c << 3) * 3; \ 71 | } while (0) 72 | 73 | 74 | /* skipNextN 75 | * --------- 76 | * Jumps forwards in the random number sequence by simulating 'n' calls to next. 77 | */ 78 | static inline void skipNextN(uint64_t *seed, uint64_t n) 79 | { 80 | uint64_t m = 1; 81 | uint64_t a = 0; 82 | uint64_t im = 0x5deece66dULL; 83 | uint64_t ia = 0xb; 84 | uint64_t k; 85 | 86 | for (k = n; k; k >>= 1) 87 | { 88 | if (k & 1) 89 | { 90 | m *= im; 91 | a = im * a + ia; 92 | } 93 | ia = (im + 1) * ia; 94 | im *= im; 95 | } 96 | 97 | *seed = *seed * m + a; 98 | *seed &= 0xffffffffffffULL; 99 | } 100 | 101 | 102 | /* Find the modular inverse: (1/x) | mod m. 103 | * Assumes x and m are positive (less than 2^63), co-prime. 104 | */ 105 | static inline __attribute__((const)) 106 | uint64_t mulInv(uint64_t x, uint64_t m) 107 | { 108 | uint64_t t, q, a, b, n; 109 | if ((int64_t)m <= 1) 110 | return 0; // no solution 111 | 112 | n = m; 113 | a = 0; b = 1; 114 | 115 | while ((int64_t)x > 1) 116 | { 117 | if (m == 0) 118 | return 0; // x and m are co-prime 119 | q = x / m; 120 | t = m; m = x % m; x = t; 121 | t = a; a = b - q * a; b = t; 122 | } 123 | 124 | if ((int64_t)b < 0) 125 | b += n; 126 | return b; 127 | } 128 | 129 | #endif /* JAVARND_H_ */ 130 | -------------------------------------------------------------------------------- /backup/cubiomes/layers.h: -------------------------------------------------------------------------------- 1 | #ifndef LAYER_H_ 2 | #define LAYER_H_ 3 | 4 | #define __STDC_FORMAT_MACROS 1 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef NULL 11 | #define NULL ((void*)0) 12 | #endif 13 | 14 | #define STRUCT(S) typedef struct S S; struct S 15 | 16 | #if __GNUC__ 17 | #define PREFETCH(PTR,RW,LOC) __builtin_prefetch(PTR,RW,LOC) 18 | #define L(COND) (__builtin_expect(!!(COND),1)) // [[likely]] 19 | #define U(COND) (__builtin_expect((COND),0)) // [[unlikely]] 20 | #else 21 | #define PREFETCH(PTR,RW,LOC) 22 | #define L(COND) (COND) 23 | #define U(COND) (COND) 24 | #endif 25 | 26 | #define LAYER_INIT_SHA (~0ULL) 27 | 28 | 29 | /* Minecraft versions */ 30 | enum MCversion 31 | { 32 | MC_1_0, MC_1_1, MC_1_2, MC_1_3, MC_1_4, MC_1_5, MC_1_6, //<1.7 Experimental! 33 | MC_1_7, MC_1_8, MC_1_9, MC_1_10, MC_1_11, MC_1_12, MC_1_13, MC_1_14, 34 | MC_1_15, MC_1_16, MC_1_17, 35 | MC_NEWEST = MC_1_17, 36 | }; 37 | 38 | enum BiomeID 39 | { 40 | none = -1, 41 | // 0 42 | ocean = 0, 43 | plains, 44 | desert, 45 | mountains, extremeHills = mountains, 46 | forest, 47 | taiga, 48 | swamp, swampland = swamp, 49 | river, 50 | nether_wastes, hell = nether_wastes, 51 | the_end, sky = the_end, 52 | // 10 53 | legacy_frozen_ocean, 54 | frozen_river, frozenRiver = frozen_river, 55 | snowy_tundra, icePlains = snowy_tundra, 56 | snowy_mountains, iceMountains = snowy_mountains, 57 | mushroom_fields, mushroomIsland = mushroom_fields, 58 | mushroom_field_shore, mushroomIslandShore = mushroom_field_shore, 59 | beach, 60 | desert_hills, desertHills = desert_hills, 61 | wooded_hills, forestHills = wooded_hills, 62 | taiga_hills, taigaHills = taiga_hills, 63 | // 20 64 | mountain_edge, extremeHillsEdge = mountain_edge, 65 | jungle, 66 | jungle_hills, jungleHills = jungle_hills, 67 | jungle_edge, jungleEdge = jungle_edge, 68 | deep_ocean, deepOcean = deep_ocean, 69 | stone_shore, stoneBeach = stone_shore, 70 | snowy_beach, coldBeach = snowy_beach, 71 | birch_forest, birchForest = birch_forest, 72 | birch_forest_hills, birchForestHills = birch_forest_hills, 73 | dark_forest, roofedForest = dark_forest, 74 | // 30 75 | snowy_taiga, coldTaiga = snowy_taiga, 76 | snowy_taiga_hills, coldTaigaHills = snowy_taiga_hills, 77 | giant_tree_taiga, megaTaiga = giant_tree_taiga, 78 | giant_tree_taiga_hills, megaTaigaHills = giant_tree_taiga_hills, 79 | wooded_mountains, extremeHillsPlus = wooded_mountains, 80 | savanna, 81 | savanna_plateau, savannaPlateau = savanna_plateau, 82 | badlands, mesa = badlands, 83 | wooded_badlands_plateau, mesaPlateau_F = wooded_badlands_plateau, 84 | badlands_plateau, mesaPlateau = badlands_plateau, 85 | // 40 -- 1.13 86 | warm_ocean, warmOcean = warm_ocean, 87 | deep_warm_ocean, warmDeepOcean = deep_warm_ocean, 88 | lukewarm_ocean, lukewarmOcean = lukewarm_ocean, 89 | deep_lukewarm_ocean, lukewarmDeepOcean = deep_lukewarm_ocean, 90 | cold_ocean, coldOcean = cold_ocean, 91 | deep_cold_ocean, coldDeepOcean = deep_cold_ocean, 92 | frozen_ocean, frozenOcean = frozen_ocean, 93 | deep_frozen_ocean, frozenDeepOcean = deep_frozen_ocean, 94 | bamboo_jungle, 95 | bamboo_jungle_hills, 96 | // 50 97 | BIOME_NUM, 98 | 99 | the_void = 127, 100 | 101 | // mutated variants 102 | sunflower_plains = plains+128, 103 | desert_lakes = desert+128, 104 | gravelly_mountains = mountains+128, 105 | flower_forest = forest+128, 106 | taiga_mountains = taiga+128, 107 | swamp_hills = swamp+128, 108 | ice_spikes = snowy_tundra+128, 109 | modified_jungle = jungle+128, 110 | modified_jungle_edge = jungle_edge+128, 111 | tall_birch_forest = birch_forest+128, 112 | tall_birch_hills = birch_forest_hills+128, 113 | dark_forest_hills = dark_forest+128, 114 | snowy_taiga_mountains = snowy_taiga+128, 115 | giant_spruce_taiga = giant_tree_taiga+128, 116 | giant_spruce_taiga_hills = giant_tree_taiga_hills+128, 117 | modified_gravelly_mountains = wooded_mountains+128, 118 | shattered_savanna = savanna+128, 119 | shattered_savanna_plateau = savanna_plateau+128, 120 | eroded_badlands = badlands+128, 121 | modified_wooded_badlands_plateau = wooded_badlands_plateau+128, 122 | modified_badlands_plateau = badlands_plateau+128, 123 | // 1.16 124 | soul_sand_valley = 178, 125 | crimson_forest = 179, 126 | warped_forest = 180, 127 | basalt_deltas = 181, 128 | // 1.17 129 | dripstone_caves = 174, 130 | lush_caves = 175, 131 | 132 | small_end_islands = the_end, 133 | end_midlands = the_end, 134 | end_highlands = the_end, 135 | end_barrens = the_end, 136 | }; 137 | 138 | 139 | enum BiomeTempCategory 140 | { 141 | Oceanic, Warm, Lush, Cold, Freezing, Special 142 | }; 143 | 144 | 145 | STRUCT(PerlinNoise) 146 | { 147 | int d[512]; 148 | double a, b, c; 149 | }; 150 | 151 | STRUCT(OctaveNoise) 152 | { 153 | double lacuna; 154 | double persist; 155 | int octcnt; 156 | PerlinNoise *octaves; 157 | }; 158 | 159 | STRUCT(DoublePerlinNoise) 160 | { 161 | double amplitude; 162 | OctaveNoise octA; 163 | OctaveNoise octB; 164 | }; 165 | 166 | struct Layer; 167 | typedef int (mapfunc_t)(const struct Layer *, int *, int, int, int, int); 168 | 169 | STRUCT(Layer) 170 | { 171 | mapfunc_t *getMap; 172 | 173 | int8_t mc; // minecraft version 174 | int8_t zoom; // zoom factor of layer 175 | int8_t edge; // maximum border required from parent layer 176 | int scale; // scale of this layer (cell = scale x scale blocks) 177 | 178 | uint64_t layerSalt; // processed salt or initialization mode 179 | uint64_t startSalt; // (depends on world seed) used to step PRNG forward 180 | uint64_t startSeed; // (depends on world seed) starting point for chunk seeds 181 | 182 | void *data; // generic data for custom layers 183 | 184 | Layer *p, *p2; // parent layers 185 | }; 186 | 187 | STRUCT(NetherNoise) 188 | { 189 | // altitude and wierdness don't affect nether biomes 190 | // and the weight is a 5th noise parameter which is constant 191 | DoublePerlinNoise temperature; 192 | DoublePerlinNoise humidity; 193 | PerlinNoise oct[8]; // buffer for octaves in double perlin noise 194 | }; 195 | 196 | typedef PerlinNoise EndNoise; 197 | 198 | STRUCT(SurfaceNoise) 199 | { 200 | double xzScale, yScale; 201 | double xzFactor, yFactor; 202 | OctaveNoise octmin; 203 | OctaveNoise octmax; 204 | OctaveNoise octmain; 205 | PerlinNoise oct[16+16+8]; 206 | }; 207 | 208 | #ifdef __cplusplus 209 | extern "C" 210 | { 211 | #endif 212 | 213 | //============================================================================== 214 | // Essentials 215 | //============================================================================== 216 | 217 | void initBiomes(); 218 | 219 | /* Applies the given world seed to the layer and all dependent layers. */ 220 | void setLayerSeed(Layer *layer, uint64_t worldSeed); 221 | 222 | 223 | //============================================================================== 224 | // Noise 225 | //============================================================================== 226 | 227 | void perlinInit(PerlinNoise *rnd); 228 | double samplePerlin(const PerlinNoise *rnd, double x, double y, double z, 229 | double yamp, double ymin); 230 | double sampleSimplex2D(const PerlinNoise *rnd, double x, double y); 231 | 232 | void octaveInit(OctaveNoise *rnd, PerlinNoise *octaves, 233 | int omin, int len); 234 | double sampleOctave(const OctaveNoise *rnd, double x, double y, double z); 235 | 236 | void doublePerlinInit(DoublePerlinNoise *rnd, 237 | PerlinNoise *octavesA, PerlinNoise *octavesB, int omin, int len); 238 | double sampleDoublePerlin(const DoublePerlinNoise *rnd, 239 | double x, double y, double z); 240 | 241 | void initSurfaceNoise(SurfaceNoise *rnd, 242 | double xzScale, double yScale, double xzFactor, double yFactor); 243 | void initSurfaceNoiseEnd(SurfaceNoise *rnd, uint64_t seed); 244 | double sampleSurfaceNoise(const SurfaceNoise *rnd, int x, int y, int z); 245 | 246 | 247 | //============================================================================== 248 | // Nether (1.16+) and End (1.9+) Biome Generation 249 | //============================================================================== 250 | 251 | /** 252 | * Nether biomes are 3D, and generated at scale 1:4. Use voronoiAccess3D() to 253 | * convert coordinates at 1:1 scale to their 1:4 access. Biome checks for 254 | * structures are generally done at y=0. 255 | * 256 | * The function getNetherBiome() determines the nether biome at a given 257 | * coordinate at scale 1:4. The parameter 'ndel' is an output noise delta for 258 | * optimization purposes and can be ignored (nullable). 259 | * 260 | * Use mapNether2D() to get a 2D area of nether biomes at y=0, scale 1:4. 261 | * 262 | * The mapNether3D() function attempts to optimize the generation of a volume 263 | * at scale 1:4, ranging from (x,y,z) to (x+w, y+yh, z+h) [exclusive] and the 264 | * output is indexed with out[y_k*(w*h) + z_j*w + x_i]. If the optimization 265 | * parameter 'confidence' has a value less than 1.0, the generation will 266 | * generally be faster, but can yield incorrect results in some circumstances. 267 | * 268 | * The output buffer for the map-functions need only be of sufficient size to 269 | * hold the generated area (i.e. w*h or w*h*yh). 270 | */ 271 | void setNetherSeed(NetherNoise *nn, uint64_t seed); 272 | int getNetherBiome(const NetherNoise *nn, int x, int y, int z, float *ndel); 273 | int mapNether2D(const NetherNoise *nn, int *out, int x, int z, int w, int h); 274 | int mapNether3D(const NetherNoise *nn, int *out, int x, int z, int w, int h, 275 | int y, int yh, int scale, float confidence); 276 | 277 | /** 278 | * End biome generation is based on simplex noise and varies only at a 1:16 279 | * chunk scale which can be generated with mapEndBiome(). The function mapEnd() 280 | * is a variation which also scales this up on a regular grid to 1:4. The final 281 | * access at a 1:1 scale is the standard voronoi layer. 282 | */ 283 | void setEndSeed(EndNoise *en, uint64_t seed); 284 | int mapEndBiome(const EndNoise *en, int *out, int x, int z, int w, int h); 285 | int mapEnd(const EndNoise *en, int *out, int x, int z, int w, int h); 286 | int getSurfaceHeightEnd(int mc, uint64_t seed, int x, int z); 287 | 288 | 289 | //============================================================================== 290 | // Seed Helpers 291 | //============================================================================== 292 | 293 | /** 294 | * The seed pipeline: 295 | * 296 | * getLayerSalt(n) -> layerSalt (ls) 297 | * layerSalt (ls), worldSeed (ws) -> startSalt (st), startSeed (ss) 298 | * startSeed (ss), coords (x,z) -> chunkSeed (cs) 299 | * 300 | * The chunkSeed alone is enough to generate the first PRNG integer with: 301 | * mcFirstInt(cs, mod) 302 | * subsequent PRNG integers are generated by stepping the chunkSeed forwards, 303 | * salted with startSalt: 304 | * cs_next = mcStepSeed(cs, st) 305 | */ 306 | 307 | static inline uint64_t mcStepSeed(uint64_t s, uint64_t salt) 308 | { 309 | return s * (s * 6364136223846793005ULL + 1442695040888963407ULL) + salt; 310 | } 311 | 312 | static inline int mcFirstInt(uint64_t s, int mod) 313 | { 314 | int ret = (int)(((int64_t)s >> 24) % mod); 315 | if (ret < 0) 316 | ret += mod; 317 | return ret; 318 | } 319 | 320 | static inline int mcFirstIsZero(uint64_t s, int mod) 321 | { 322 | return (int)(((int64_t)s >> 24) % mod) == 0; 323 | } 324 | 325 | static inline uint64_t getChunkSeed(uint64_t ss, int x, int z) 326 | { 327 | uint64_t cs = ss + x; 328 | cs = mcStepSeed(cs, z); 329 | cs = mcStepSeed(cs, x); 330 | cs = mcStepSeed(cs, z); 331 | return cs; 332 | } 333 | 334 | static inline uint64_t getLayerSalt(uint64_t salt) 335 | { 336 | uint64_t ls = mcStepSeed(salt, salt); 337 | ls = mcStepSeed(ls, salt); 338 | ls = mcStepSeed(ls, salt); 339 | return ls; 340 | } 341 | 342 | static inline uint64_t getStartSalt(uint64_t ws, uint64_t ls) 343 | { 344 | uint64_t st = ws; 345 | st = mcStepSeed(st, ls); 346 | st = mcStepSeed(st, ls); 347 | st = mcStepSeed(st, ls); 348 | return st; 349 | } 350 | 351 | static inline uint64_t getStartSeed(uint64_t ws, uint64_t ls) 352 | { 353 | uint64_t ss = ws; 354 | ss = getStartSalt(ss, ls); 355 | ss = mcStepSeed(ss, 0); 356 | return ss; 357 | } 358 | 359 | 360 | //============================================================================== 361 | // BiomeID Helpers 362 | //============================================================================== 363 | 364 | int biomeExists(int mc, int id); 365 | int isOverworld(int mc, int id); 366 | int getMutated(int mc, int id); 367 | int getCategory(int mc, int id); 368 | int areSimilar(int mc, int id1, int id2); 369 | int isMesa(int id); 370 | int isShallowOcean(int id); 371 | int isDeepOcean(int id); 372 | int isOceanic(int id); 373 | int isSnowy(int id); 374 | 375 | 376 | //============================================================================== 377 | // Layers 378 | //============================================================================== 379 | 380 | // old names 381 | mapfunc_t mapContinent; // mapIsland 382 | mapfunc_t mapZoomFuzzy; 383 | mapfunc_t mapZoom; 384 | mapfunc_t mapLand; // mapAddIsland 385 | mapfunc_t mapLand16; 386 | mapfunc_t mapIsland; // mapRemoveTooMuchOcean 387 | mapfunc_t mapSnow; // mapAddSnow 388 | mapfunc_t mapSnow16; 389 | mapfunc_t mapCool; // mapCoolWarm 390 | mapfunc_t mapHeat; // mapHeatIce 391 | mapfunc_t mapSpecial; 392 | mapfunc_t mapMushroom; // mapAddMushroomIsland 393 | mapfunc_t mapDeepOcean; 394 | mapfunc_t mapBiome; 395 | mapfunc_t mapBamboo; // mapAddBamboo 396 | mapfunc_t mapNoise; // mapRiverInit 397 | mapfunc_t mapBiomeEdge; 398 | mapfunc_t mapHills; 399 | mapfunc_t mapRiver; 400 | mapfunc_t mapSmooth; 401 | mapfunc_t mapSunflower; // mapRareBiome 402 | mapfunc_t mapShore; 403 | mapfunc_t mapSwampRiver; 404 | mapfunc_t mapRiverMix; 405 | mapfunc_t mapOceanTemp; 406 | mapfunc_t mapOceanMix; 407 | mapfunc_t mapOceanEdge; // BE function 408 | 409 | // final layer 1:1 410 | mapfunc_t mapVoronoi; // mapVoronoiZoom 411 | 412 | // With 1.15 voronoi changed in preparation for 3D biome generation. 413 | // Biome generation now stops at scale 1:4 OceanMix and voronoi is just an 414 | // access algorithm, mapping the 1:1 scale onto its 1:4 correspondent. 415 | // It is seeded by the first 8-bytes of the SHA-256 hash of the world seed. 416 | void voronoiAccess3D(uint64_t sha, int x, int y, int z, int *x4, int *y4, int *z4); 417 | 418 | 419 | #ifdef __cplusplus 420 | } 421 | #endif 422 | 423 | #endif /* LAYER_H_ */ 424 | -------------------------------------------------------------------------------- /backup/cubiomes/mcrandom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The Mersenne Twister pseudo-random number generator (PRNG) 3 | * 4 | * This is an implementation of fast PRNG called MT19937, meaning it has a 5 | * period of 2^19937-1, which is a Mersenne prime. 6 | * 7 | * This PRNG is fast and suitable for non-cryptographic code. For instance, it 8 | * would be perfect for Monte Carlo simulations, etc. 9 | * 10 | * For all the details on this algorithm, see the original paper: 11 | * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf 12 | * 13 | * Written by Christian Stigen Larsen 14 | * Distributed under the modified BSD license. 15 | * 2015-02-17, 2017-12-06 16 | */ 17 | 18 | #include 19 | #include "mcrandom.h" 20 | 21 | /* 22 | * We have an array of 624 32-bit values, and there are 31 unused bits, so we 23 | * have a seed value of 624*32-31 = 19937 bits. 24 | */ 25 | #define SIZE 624 26 | #define PERIOD 397 27 | #define DIFF (SIZE - PERIOD) 28 | 29 | static const uint32_t MAGIC = 0x9908b0df; 30 | 31 | // State for a singleton Mersenne Twister. If you want to make this into a 32 | // class, these are what you need to isolate. 33 | struct MTState_ { 34 | uint32_t MT[SIZE]; 35 | uint32_t MT_TEMPERED[SIZE]; 36 | size_t index; 37 | }; 38 | 39 | typedef struct MTState_ MTState; 40 | 41 | static MTState state; 42 | 43 | #define M32(x) (0x80000000 & x) // 32nd MSB 44 | #define L31(x) (0x7FFFFFFF & x) // 31 LSBs 45 | 46 | #define UNROLL(expr) \ 47 | y = M32(state.MT[i]) | L31(state.MT[i+1]); \ 48 | state.MT[i] = state.MT[expr] ^ (y >> 1) ^ ((((int32_t)((y) << 31)) >> 31) & MAGIC); \ 49 | ++i; 50 | 51 | static void generate_numbers() 52 | { 53 | /* 54 | * For performance reasons, we've unrolled the loop three times, thus 55 | * mitigating the need for any modulus operations. Anyway, it seems this 56 | * trick is old hat: http://www.quadibloc.com/crypto/co4814.htm 57 | */ 58 | 59 | size_t i = 0; 60 | uint32_t y; 61 | 62 | // i = [0 ... 226] 63 | while ( i < DIFF ) { 64 | /* 65 | * We're doing 226 = 113*2, an even number of steps, so we can safely 66 | * unroll one more step here for speed: 67 | */ 68 | UNROLL(i+PERIOD); 69 | } 70 | 71 | // i = [227 ... 622] 72 | while ( i < SIZE -1 ) { 73 | /* 74 | * 623-227 = 396 = 2*2*3*3*11, so we can unroll this loop in any number 75 | * that evenly divides 396 (2, 4, 6, etc). Here we'll unroll 11 times. 76 | */ 77 | UNROLL(i-DIFF); 78 | } 79 | 80 | { 81 | // i = 623, last step rolls over 82 | y = M32(state.MT[SIZE-1]) | L31(state.MT[0]); 83 | state.MT[SIZE-1] = state.MT[PERIOD-1] ^ (y >> 1) ^ ((((int32_t)((y) << 31)) >> 84 | 31) & MAGIC); 85 | } 86 | 87 | // Temper all numbers in a batch 88 | for (size_t i = 0; i < SIZE; ++i) { 89 | y = state.MT[i]; 90 | y ^= y >> 11; 91 | y ^= y << 7 & 0x9d2c5680; 92 | y ^= y << 15 & 0xefc60000; 93 | y ^= y >> 18; 94 | state.MT_TEMPERED[i] = y; 95 | } 96 | 97 | state.index = 0; 98 | } 99 | 100 | void mcrandom_seed(uint32_t value) 101 | { 102 | /* 103 | * The equation below is a linear congruential generator (LCG), one of the 104 | * oldest known pseudo-random number generator algorithms, in the form 105 | * X_(n+1) = = (a*X_n + c) (mod m). 106 | * 107 | * We've implicitly got m=32 (mask + word size of 32 bits), so there is no 108 | * need to explicitly use modulus. 109 | * 110 | * What is interesting is the multiplier a. The one we have below is 111 | * 0x6c07865 --- 1812433253 in decimal, and is called the Borosh-Niederreiter 112 | * multiplier for modulus 2^32. 113 | * 114 | * It is mentioned in passing in Knuth's THE ART OF COMPUTER 115 | * PROGRAMMING, Volume 2, page 106, Table 1, line 13. LCGs are 116 | * treated in the same book, pp. 10-26 117 | * 118 | * You can read the original paper by Borosh and Niederreiter as well. It's 119 | * called OPTIMAL MULTIPLIERS FOR PSEUDO-RANDOM NUMBER GENERATION BY THE 120 | * LINEAR CONGRUENTIAL METHOD (1983) at 121 | * http://www.springerlink.com/content/n7765ku70w8857l7/ 122 | * 123 | * You can read about LCGs at: 124 | * http://en.wikipedia.org/wiki/Linear_congruential_generator 125 | * 126 | * From that page, it says: "A common Mersenne twister implementation, 127 | * interestingly enough, uses an LCG to generate seed data.", 128 | * 129 | * Since we're using 32-bits data types for our MT array, we can skip the 130 | * masking with 0xFFFFFFFF below. 131 | */ 132 | 133 | state.MT[0] = value; 134 | state.index = SIZE; 135 | 136 | for ( uint_fast32_t i=1; i>30) + i; 138 | } 139 | 140 | uint32_t mcrandom_next() 141 | { 142 | if ( state.index == SIZE ) { 143 | generate_numbers(); 144 | state.index = 0; 145 | } 146 | 147 | return state.MT_TEMPERED[state.index++]; 148 | } 149 | -------------------------------------------------------------------------------- /backup/cubiomes/mcrandom.h: -------------------------------------------------------------------------------- 1 | #ifndef MCRANDOM_H_ 2 | #define MCRANDOM_H_ 3 | 4 | #define __STDC_LIMIT_MACROS 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /* 12 | * Extract a pseudo-random unsigned 32-bit integer in the range 0 ... UINT32_MAX 13 | */ 14 | uint32_t mcrandom_next(); 15 | 16 | /* 17 | * Initialize Mersenne Twister with given seed value. 18 | */ 19 | void mcrandom_seed(uint32_t seed_value); 20 | 21 | 22 | static inline void setSeed(uint32_t value) 23 | { 24 | mcrandom_seed(value); 25 | } 26 | 27 | static inline int nextInt(const int n) 28 | { 29 | return mcrandom_next() % n; 30 | } 31 | 32 | static inline double nextDouble() { 33 | return mcrandom_next()/4294967296.0; 34 | } 35 | 36 | static inline float nextFloat() { 37 | return nextDouble(); 38 | } 39 | 40 | static inline void skipNextN(int n) { 41 | for(int i=0;i 5 | #include 6 | #include 7 | 8 | uint32_t hash32(uint32_t x) 9 | { 10 | x ^= x >> 15; 11 | x *= 0xd168aaad; 12 | x ^= x >> 15; 13 | x *= 0xaf723597; 14 | x ^= x >> 15; 15 | return x; 16 | } 17 | 18 | double now() 19 | { 20 | struct timespec t; 21 | clock_gettime(CLOCK_MONOTONIC, &t); 22 | return t.tv_sec + t.tv_nsec * 1e-9; 23 | } 24 | 25 | /* Runs a performance test using function f(). The function should take a 26 | * number of trial runs and a data argument [dat], and return an arbitrary 27 | * consumable value (useful to avoid ommission by optimization). 28 | * The minimum and mean times for a trial run will be stored in tmin and tavg. 29 | * The benchmark aims to take just over one second. 30 | * Returned is the total number of trials performed. 31 | */ 32 | int64_t 33 | benchmark(int64_t (*f)(int64_t n, void*), void *dat, double *tmin, double *tavg) 34 | { 35 | const double maxt = 1.0; 36 | const double mintt = 1e-2; 37 | int64_t cnt = 0; 38 | int64_t ntt = 1; 39 | int64_t consume = 0; 40 | double t, _tavg = 0, _tmin = DBL_MAX; 41 | 42 | for (ntt = 1; ; ntt *= 2) 43 | { 44 | t = -now(); 45 | consume ^= f(ntt, dat); 46 | t += now(); 47 | if (t >= mintt) 48 | break; 49 | } 50 | do 51 | { 52 | t = -now(); 53 | consume ^= f(ntt, dat); 54 | t += now(); 55 | cnt++; 56 | _tavg += t; 57 | if (t < _tmin) 58 | _tmin = t; 59 | } 60 | while (_tavg < maxt); 61 | 62 | cnt *= ntt; 63 | if (tmin) *tmin = _tmin / ntt; 64 | if (tavg) *tavg = _tavg / cnt; 65 | 66 | static volatile int64_t v_consume; 67 | v_consume ^= consume; 68 | return cnt; 69 | } 70 | 71 | uint32_t getRef(int mc, int bits, const char *path) 72 | { 73 | initBiomes(); 74 | LayerStack g; 75 | setupGenerator(&g, mc); 76 | Layer *l = g.entry_4; 77 | int *ids = allocCache(l, 1, 1); 78 | 79 | FILE *fp = NULL; 80 | if (path) 81 | fp = fopen(path, "w"); 82 | 83 | int r = 1 << (bits-1); 84 | int h = 0; 85 | int x, z; 86 | for (x = -r; x < r; x++) 87 | { 88 | for (z = -r; z < r; z++) 89 | { 90 | int64_t s = (int64_t)( (z << bits) ^ x ); 91 | setLayerSeed(l, s); 92 | //applySeed(&g, s); 93 | genArea(l, ids, x, z, 1, 1); 94 | h ^= hash32( (int) s ^ (ids[0] << 2*bits) ); 95 | 96 | if (fp) 97 | fprintf(fp, "%5d%6d%4d\n", x, z, ids[0]); 98 | } 99 | } 100 | if (fp) 101 | fclose(fp); 102 | free(ids); 103 | return h; 104 | } 105 | 106 | int testBiomeGen1x1(const int *mc, const uint32_t *expect, int bits, int cnt) 107 | { 108 | int test; 109 | uint32_t h; 110 | int ok = 1; 111 | 112 | for (test = 0; test < cnt; test++) 113 | { 114 | printf(" [%d/%d] MC 1.%-2d: expecting %08x ... ", 115 | test+1, cnt, mc[test], expect[test]); 116 | fflush(stdout); 117 | 118 | h = getRef(mc[test], bits, NULL); 119 | printf("got %08x %s\e[0m\n", 120 | h, h == expect[test] ? "\e[1;92mOK" : "\e[1;91mFAILED"); 121 | ok &= (h == expect[test]); 122 | } 123 | 124 | return ok; 125 | } 126 | 127 | int testOverworldBiomes() 128 | { 129 | const int mc_vers[] = { 130 | MC_1_16, MC_1_15, MC_1_13, MC_1_12, MC_1_9, MC_1_7, 131 | MC_1_6, 132 | }; 133 | const uint32_t b6_hashes[] = { 134 | 0xde9a6574, 0x3a568a6d, 0x96c97323, 0xbc75e996, 0xe27a45a2, 0xbc75e996, 135 | 0x15b47206, 136 | }; 137 | const uint32_t b10_hashes[] = { 138 | 0xfdede71d, 0xca8005d7, 0x399f7cc8, 0xb3363967, 0x17e5592f, 0xb3363967, 139 | 0xa52e377c, 140 | }; 141 | const int testcnt = sizeof(mc_vers) / sizeof(int); 142 | 143 | printf("Testing 1x1 biome generation (quick):\n"); 144 | if (!testBiomeGen1x1(mc_vers, b6_hashes, 6, testcnt)) 145 | return -1; 146 | 147 | printf("Testing 1x1 biome generation (thorough):\n"); 148 | if (!testBiomeGen1x1(mc_vers, b10_hashes, 10, testcnt)) 149 | return -1; 150 | 151 | return 0; 152 | } 153 | 154 | 155 | int gw = 16, gh = 16; 156 | 157 | int64_t testPerfEnd(int64_t n, void *data) 158 | { 159 | EndNoise *en = (EndNoise*) data; 160 | int ids[gw*gh]; 161 | int64_t r = 0; 162 | 163 | while (n-->0) 164 | { 165 | int x = rand() % 10000 - 5000; 166 | int z = rand() % 10000 - 5000; 167 | mapEndBiome(en, ids, x, z, gw, gh); 168 | r ^= ids[0]; 169 | } 170 | return r; 171 | } 172 | 173 | int64_t testPerfNether(int64_t n, void *data) 174 | { 175 | NetherNoise *nn = (NetherNoise*) data; 176 | int ids[gw*gh]; 177 | int64_t r = 0; 178 | 179 | while (n-->0) 180 | { 181 | int x = rand() % 10000 - 5000; 182 | int z = rand() % 10000 - 5000; 183 | mapNether2D(nn, ids, x, z, gw, gh); 184 | r ^= ids[0]; 185 | } 186 | return r; 187 | } 188 | 189 | int testPerformance() 190 | { 191 | double tmin, tavg; 192 | 193 | EndNoise en; 194 | setEndSeed(&en, 12345); 195 | benchmark(testPerfEnd, &en, &tmin, &tavg); 196 | printf("End %dx%d -> min:%10.0lf ns | avg:%10.0lf ns | conf:%4.2lf %%\n", 197 | gw, gh, 1e9*tmin, 1e9*tavg, 100 * (tavg-tmin) / (tavg+tmin)); 198 | 199 | NetherNoise nn; 200 | setNetherSeed(&nn, 12345); 201 | benchmark(testPerfNether, &nn, &tmin, &tavg); 202 | printf("Nether %dx%d -> min:%10.0lf ns | avg:%10.0lf ns | conf:%4.2lf %%\n", 203 | gw, gh, 1e9*tmin, 1e9*tavg, 100 * (tavg-tmin) / (tavg+tmin)); 204 | } 205 | 206 | 207 | int main() 208 | { 209 | //testOverworldBiomes(); 210 | testPerformance(); 211 | return 0; 212 | } 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /backup/cubiomes/util.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "layers.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | const char* mc2str(int mc) 9 | { 10 | switch (mc) 11 | { 12 | case MC_1_6: return "1.6"; break; 13 | case MC_1_7: return "1.7"; break; 14 | case MC_1_8: return "1.8"; break; 15 | case MC_1_9: return "1.9"; break; 16 | case MC_1_10: return "1.10"; break; 17 | case MC_1_11: return "1.11"; break; 18 | case MC_1_12: return "1.12"; break; 19 | case MC_1_13: return "1.13"; break; 20 | case MC_1_14: return "1.14"; break; 21 | case MC_1_15: return "1.15"; break; 22 | case MC_1_16: return "1.16"; break; 23 | case MC_1_17: return "1.17"; break; 24 | default: return NULL; 25 | } 26 | } 27 | 28 | int str2mc(const char *s) 29 | { 30 | if (!strcmp(s, "1.17")) return MC_1_17; 31 | if (!strcmp(s, "1.16")) return MC_1_16; 32 | if (!strcmp(s, "1.15")) return MC_1_15; 33 | if (!strcmp(s, "1.14")) return MC_1_14; 34 | if (!strcmp(s, "1.13")) return MC_1_13; 35 | if (!strcmp(s, "1.12")) return MC_1_12; 36 | if (!strcmp(s, "1.11")) return MC_1_11; 37 | if (!strcmp(s, "1.10")) return MC_1_10; 38 | if (!strcmp(s, "1.9")) return MC_1_9; 39 | if (!strcmp(s, "1.8")) return MC_1_8; 40 | if (!strcmp(s, "1.7")) return MC_1_7; 41 | if (!strcmp(s, "1.6")) return MC_1_6; 42 | return -1; 43 | } 44 | 45 | 46 | const char *biome2str(int id) 47 | { 48 | switch (id) 49 | { 50 | case ocean: return "ocean"; 51 | case plains: return "plains"; 52 | case desert: return "desert"; 53 | case mountains: return "mountains"; 54 | case forest: return "forest"; 55 | case taiga: return "taiga"; 56 | case swamp: return "swamp"; 57 | case river: return "river"; 58 | case nether_wastes: return "nether_wastes"; 59 | case the_end: return "the_end"; 60 | // 10 61 | case frozen_ocean: return "frozen_ocean"; 62 | case frozen_river: return "frozen_river"; 63 | case snowy_tundra: return "snowy_tundra"; 64 | case snowy_mountains: return "snowy_mountains"; 65 | case mushroom_fields: return "mushroom_fields"; 66 | case mushroom_field_shore: return "mushroom_field_shore"; 67 | case beach: return "beach"; 68 | case desert_hills: return "desert_hills"; 69 | case wooded_hills: return "wooded_hills"; 70 | case taiga_hills: return "taiga_hills"; 71 | // 20 72 | case mountain_edge: return "mountain_edge"; 73 | case jungle: return "jungle"; 74 | case jungle_hills: return "jungle_hills"; 75 | case jungle_edge: return "jungle_edge"; 76 | case deep_ocean: return "deep_ocean"; 77 | case stone_shore: return "stone_shore"; 78 | case snowy_beach: return "snowy_beach"; 79 | case birch_forest: return "birch_forest"; 80 | case birch_forest_hills: return "birch_forest_hills"; 81 | case dark_forest: return "dark_forest"; 82 | // 30 83 | case snowy_taiga: return "snowy_taiga"; 84 | case snowy_taiga_hills: return "snowy_taiga_hills"; 85 | case giant_tree_taiga: return "giant_tree_taiga"; 86 | case giant_tree_taiga_hills: return "giant_tree_taiga_hills"; 87 | case wooded_mountains: return "wooded_mountains"; 88 | case savanna: return "savanna"; 89 | case savanna_plateau: return "savanna_plateau"; 90 | case badlands: return "badlands"; 91 | case wooded_badlands_plateau: return "wooded_badlands_plateau"; 92 | case badlands_plateau: return "badlands_plateau"; 93 | // 40 -- 1.13 94 | // case small_end_islands: return "small_end_islands"; 95 | // case end_midlands: return "end_midlands"; 96 | // case end_highlands: return "end_highlands"; 97 | // case end_barrens: return "end_barrens"; 98 | case warm_ocean: return "warm_ocean"; 99 | case lukewarm_ocean: return "lukewarm_ocean"; 100 | case cold_ocean: return "cold_ocean"; 101 | case deep_warm_ocean: return "deep_warm_ocean"; 102 | case deep_lukewarm_ocean: return "deep_lukewarm_ocean"; 103 | case deep_cold_ocean: return "deep_cold_ocean"; 104 | // 50 105 | case deep_frozen_ocean: return "deep_frozen_ocean"; 106 | 107 | case the_void: return "the_void"; 108 | 109 | // mutated variants 110 | case sunflower_plains: return "sunflower_plains"; 111 | case desert_lakes: return "desert_lakes"; 112 | case gravelly_mountains: return "gravelly_mountains"; 113 | case flower_forest: return "flower_forest"; 114 | case taiga_mountains: return "taiga_mountains"; 115 | case swamp_hills: return "swamp_hills"; 116 | case ice_spikes: return "ice_spikes"; 117 | case modified_jungle: return "modified_jungle"; 118 | case modified_jungle_edge: return "modified_jungle_edge"; 119 | case tall_birch_forest: return "tall_birch_forest"; 120 | case tall_birch_hills: return "tall_birch_hills"; 121 | case dark_forest_hills: return "dark_forest_hills"; 122 | case snowy_taiga_mountains: return "snowy_taiga_mountains"; 123 | case giant_spruce_taiga: return "giant_spruce_taiga"; 124 | case giant_spruce_taiga_hills: return "giant_spruce_taiga_hills"; 125 | case modified_gravelly_mountains: return "modified_gravelly_mountains"; 126 | case shattered_savanna: return "shattered_savanna"; 127 | case shattered_savanna_plateau: return "shattered_savanna_plateau"; 128 | case eroded_badlands: return "eroded_badlands"; 129 | case modified_wooded_badlands_plateau: return "modified_wooded_badlands_plateau"; 130 | case modified_badlands_plateau: return "modified_badlands_plateau"; 131 | // 1.14 132 | case bamboo_jungle: return "bamboo_jungle"; 133 | case bamboo_jungle_hills: return "bamboo_jungle_hills"; 134 | // 1.16 135 | case soul_sand_valley: return "soul_sand_valley"; 136 | case crimson_forest: return "crimson_forest"; 137 | case warped_forest: return "warped_forest"; 138 | case basalt_deltas: return "basalt_deltas"; 139 | // 1.17 140 | case dripstone_caves: return "dripstone_caves"; 141 | case lush_caves: return "lush_caves"; 142 | } 143 | return NULL; 144 | } 145 | 146 | void setBiomeColor(unsigned char biomeColor[256][3], int id, 147 | unsigned char r, unsigned char g, unsigned char b) 148 | { 149 | biomeColor[id][0] = r; 150 | biomeColor[id][1] = g; 151 | biomeColor[id][2] = b; 152 | } 153 | 154 | void setMutationColor(unsigned char biomeColor[256][3], int mutated, int parent) 155 | { 156 | unsigned int c; 157 | biomeColor[mutated][0] = (c = biomeColor[parent][0] + 40) > 255 ? 255 : c; 158 | biomeColor[mutated][1] = (c = biomeColor[parent][1] + 40) > 255 ? 255 : c; 159 | biomeColor[mutated][2] = (c = biomeColor[parent][2] + 40) > 255 ? 255 : c; 160 | } 161 | 162 | void initBiomeColors(unsigned char biomeColors[256][3]) 163 | { 164 | // This coloring scheme is largely inspired by the AMIDST program: 165 | // https://github.com/toolbox4minecraft/amidst 166 | // https://sourceforge.net/projects/amidst.mirror/ 167 | 168 | memset(biomeColors, 0, 256*3); 169 | 170 | setBiomeColor(biomeColors, ocean, 0, 0, 112); 171 | setBiomeColor(biomeColors, plains, 141, 179, 96); 172 | setBiomeColor(biomeColors, desert, 250, 148, 24); 173 | setBiomeColor(biomeColors, mountains, 96, 96, 96); 174 | setBiomeColor(biomeColors, forest, 5, 102, 33); 175 | setBiomeColor(biomeColors, taiga, 11, 102, 89); 176 | setBiomeColor(biomeColors, swamp, 7, 249, 178); 177 | setBiomeColor(biomeColors, river, 0, 0, 255); 178 | setBiomeColor(biomeColors, nether_wastes, 87, 37, 38); 179 | setBiomeColor(biomeColors, the_end, 128, 128, 255); 180 | setBiomeColor(biomeColors, frozen_ocean, 112, 112, 214); 181 | setBiomeColor(biomeColors, frozen_river, 160, 160, 255); 182 | setBiomeColor(biomeColors, snowy_tundra, 255, 255, 255); 183 | setBiomeColor(biomeColors, snowy_mountains, 160, 160, 160); 184 | setBiomeColor(biomeColors, mushroom_fields, 255, 0, 255); 185 | setBiomeColor(biomeColors, mushroom_field_shore, 160, 0, 255); 186 | setBiomeColor(biomeColors, beach, 250, 222, 85); 187 | setBiomeColor(biomeColors, desert_hills, 210, 95, 18); 188 | setBiomeColor(biomeColors, wooded_hills, 34, 85, 28); 189 | setBiomeColor(biomeColors, taiga_hills, 22, 57, 51); 190 | setBiomeColor(biomeColors, mountain_edge, 114, 120, 154); 191 | setBiomeColor(biomeColors, jungle, 83, 123, 9); 192 | setBiomeColor(biomeColors, jungle_hills, 44, 66, 5); 193 | setBiomeColor(biomeColors, jungleEdge, 98, 139, 23); 194 | setBiomeColor(biomeColors, deep_ocean, 0, 0, 48); 195 | setBiomeColor(biomeColors, stone_shore, 162, 162, 132); 196 | setBiomeColor(biomeColors, snowy_beach, 250, 240, 192); 197 | setBiomeColor(biomeColors, birch_forest, 48, 116, 68); 198 | setBiomeColor(biomeColors, birch_forest_hills, 31, 95, 50); 199 | setBiomeColor(biomeColors, dark_forest, 64, 81, 26); 200 | setBiomeColor(biomeColors, snowy_taiga, 49, 85, 74); 201 | setBiomeColor(biomeColors, snowy_taiga_hills, 36, 63, 54); 202 | setBiomeColor(biomeColors, giant_tree_taiga, 89, 102, 81); 203 | setBiomeColor(biomeColors, giant_tree_taiga_hills, 69, 79, 62); 204 | setBiomeColor(biomeColors, wooded_mountains, 80, 112, 80); 205 | setBiomeColor(biomeColors, savanna, 189, 178, 95); 206 | setBiomeColor(biomeColors, savanna_plateau, 167, 157, 100); 207 | setBiomeColor(biomeColors, badlands, 217, 69, 21); 208 | setBiomeColor(biomeColors, wooded_badlands_plateau, 176, 151, 101); 209 | setBiomeColor(biomeColors, badlands_plateau, 202, 140, 101); 210 | 211 | setBiomeColor(biomeColors, small_end_islands, 75, 75, 171); 212 | setBiomeColor(biomeColors, end_midlands, 201, 201, 89); 213 | setBiomeColor(biomeColors, end_highlands, 181, 181, 54); 214 | setBiomeColor(biomeColors, end_barrens, 112, 112, 204); 215 | 216 | setBiomeColor(biomeColors, warm_ocean, 0, 0, 172); 217 | setBiomeColor(biomeColors, lukewarm_ocean, 0, 0, 144); 218 | setBiomeColor(biomeColors, cold_ocean, 32, 32, 112); 219 | setBiomeColor(biomeColors, deep_warm_ocean, 0, 0, 80); 220 | setBiomeColor(biomeColors, deep_lukewarm_ocean, 0, 0, 64); 221 | setBiomeColor(biomeColors, deep_cold_ocean, 32, 32, 56); 222 | setBiomeColor(biomeColors, deep_frozen_ocean, 64, 64, 144); 223 | 224 | setBiomeColor(biomeColors, the_void, 0, 0, 0); 225 | 226 | setMutationColor(biomeColors, sunflower_plains, plains); 227 | setMutationColor(biomeColors, desert_lakes, desert); 228 | setMutationColor(biomeColors, gravelly_mountains, mountains); 229 | setMutationColor(biomeColors, flower_forest, forest); 230 | setMutationColor(biomeColors, taiga_mountains, taiga); 231 | setMutationColor(biomeColors, swamp_hills, swamp); 232 | setBiomeColor(biomeColors, ice_spikes, 180, 220, 220); 233 | setMutationColor(biomeColors, modified_jungle, jungle); 234 | setMutationColor(biomeColors, modified_jungle_edge, jungle_edge); 235 | setMutationColor(biomeColors, tall_birch_forest, birch_forest); 236 | setMutationColor(biomeColors, tall_birch_hills, birch_forest_hills); 237 | setMutationColor(biomeColors, dark_forest_hills, dark_forest); 238 | setMutationColor(biomeColors, snowy_taiga_mountains, snowy_taiga); 239 | setMutationColor(biomeColors, giant_spruce_taiga, giant_tree_taiga); 240 | setMutationColor(biomeColors, giant_spruce_taiga_hills, giant_tree_taiga_hills); 241 | setMutationColor(biomeColors, modified_gravelly_mountains, wooded_mountains); 242 | setMutationColor(biomeColors, shattered_savanna, savanna); 243 | setMutationColor(biomeColors, shattered_savanna_plateau, savanna_plateau); 244 | setMutationColor(biomeColors, eroded_badlands, badlands); 245 | setMutationColor(biomeColors, modified_wooded_badlands_plateau, wooded_badlands_plateau); 246 | setMutationColor(biomeColors, modified_badlands_plateau, badlands_plateau); 247 | 248 | setBiomeColor(biomeColors, bamboo_jungle, 118, 142, 20); 249 | setBiomeColor(biomeColors, bamboo_jungle_hills, 59, 71, 10); 250 | 251 | setBiomeColor(biomeColors, soul_sand_valley, 77, 58, 46); 252 | setBiomeColor(biomeColors, crimson_forest, 152, 26, 17); 253 | setBiomeColor(biomeColors, warped_forest, 73, 144, 123); 254 | setBiomeColor(biomeColors, basalt_deltas, 100, 95, 99); 255 | 256 | setBiomeColor(biomeColors, dripstone_caves, 149, 127, 104); // TBD 257 | setBiomeColor(biomeColors, lush_caves, 109, 143, 62); // TBD 258 | } 259 | 260 | void initBiomeTypeColors(unsigned char biomeColors[256][3]) 261 | { 262 | memset(biomeColors, 0, 256*3); 263 | 264 | setBiomeColor(biomeColors, Oceanic, 0x00, 0x00, 0xa0); 265 | setBiomeColor(biomeColors, Warm, 0xff, 0xc0, 0x00); 266 | setBiomeColor(biomeColors, Lush, 0x00, 0xa0, 0x00); 267 | setBiomeColor(biomeColors, Cold, 0x60, 0x60, 0x60); 268 | setBiomeColor(biomeColors, Freezing, 0xff, 0xff, 0xff); 269 | } 270 | 271 | 272 | int biomesToImage(unsigned char *pixels, 273 | unsigned char biomeColors[256][3], const int *biomes, 274 | const unsigned int sx, const unsigned int sy, 275 | const unsigned int pixscale, const int flip) 276 | { 277 | unsigned int i, j; 278 | int containsInvalidBiomes = 0; 279 | 280 | for (j = 0; j < sy; j++) 281 | { 282 | for (i = 0; i < sx; i++) 283 | { 284 | int id = biomes[j*sx+i]; 285 | unsigned int r, g, b; 286 | 287 | if (id < 0 || id >= 256) 288 | { 289 | // This may happen for some intermediate layers 290 | containsInvalidBiomes = 1; 291 | r = biomeColors[id&0x7f][0]-40; r = (r>0xff) ? 0x00 : r&0xff; 292 | g = biomeColors[id&0x7f][1]-40; g = (g>0xff) ? 0x00 : g&0xff; 293 | b = biomeColors[id&0x7f][2]-40; b = (b>0xff) ? 0x00 : b&0xff; 294 | } 295 | else 296 | { 297 | r = biomeColors[id][0]; 298 | g = biomeColors[id][1]; 299 | b = biomeColors[id][2]; 300 | } 301 | 302 | unsigned int m, n; 303 | for (m = 0; m < pixscale; m++) { 304 | for (n = 0; n < pixscale; n++) { 305 | int idx = pixscale * i + n; 306 | if (flip) 307 | idx += (sx * pixscale) * ((pixscale * j) + m); 308 | else 309 | idx += (sx * pixscale) * ((pixscale * (sy-1-j)) + m); 310 | 311 | unsigned char *pix = pixels + 3*idx; 312 | pix[0] = (unsigned char)r; 313 | pix[1] = (unsigned char)g; 314 | pix[2] = (unsigned char)b; 315 | } 316 | } 317 | } 318 | } 319 | 320 | return containsInvalidBiomes; 321 | } 322 | 323 | int savePPM(const char *path, const unsigned char *pixels, const unsigned int sx, const unsigned int sy) 324 | { 325 | FILE *fp = fopen(path, "wb"); 326 | if (!fp) 327 | return -1; 328 | fprintf(fp, "P6\n%d %d\n255\n", sx, sy); 329 | int written = fwrite(pixels, sx*sy, 3, fp); 330 | fclose(fp); 331 | return (unsigned int)written != 3*sx*sy; 332 | } 333 | 334 | -------------------------------------------------------------------------------- /backup/cubiomes/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H_ 2 | #define UTIL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | const char* mc2str(int mc); 10 | int str2mc(const char *s); 11 | 12 | const char *biome2str(int id); 13 | void initBiomeColors(unsigned char biomeColors[256][3]); 14 | void initBiomeTypeColors(unsigned char biomeColors[256][3]); 15 | 16 | int biomesToImage(unsigned char *pixels, 17 | unsigned char biomeColors[256][3], const int *biomes, 18 | const unsigned int sx, const unsigned int sy, 19 | const unsigned int pixscale, const int flip); 20 | 21 | int savePPM(const char* path, const unsigned char *pixels, 22 | const unsigned int sx, const unsigned int sy); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /backup/finder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/20. 3 | // 4 | 5 | #include "finder.h" 6 | #include "structure.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "be_random.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | constexpr Pos CENTER = {0, 0}; 23 | constexpr int SEARCH_RADIUS = 4; 24 | constexpr int AREA_NUM = (SEARCH_RADIUS * 2 + 1) * (SEARCH_RADIUS * 2 + 1); 25 | 26 | struct SearchArea { 27 | constexpr SearchArea() : poses() { 28 | int index = 0; 29 | for (int i = -SEARCH_RADIUS; i <= SEARCH_RADIUS; i++) { 30 | for (int j = -SEARCH_RADIUS; j <= SEARCH_RADIUS; j++) { 31 | poses[index].x = CENTER.x + i; 32 | poses[index].z = CENTER.z + j; 33 | ++index; 34 | } 35 | } 36 | } 37 | 38 | Pos poses[AREA_NUM]; 39 | }; 40 | 41 | 42 | uint32_t cal_candicate_seed(int x, int z) { 43 | return 10387313 - 245998635 * z - 1724254968 * x; 44 | } 45 | 46 | struct CachedCandicateAreaSeed { 47 | constexpr CachedCandicateAreaSeed() : seeds() { 48 | 49 | } 50 | 51 | uint32_t seeds[AREA_NUM]; 52 | }; 53 | 54 | 55 | struct CandicateStructurePos { 56 | Pos p{}; 57 | int valid = -1; 58 | }; 59 | 60 | namespace { 61 | 62 | uint32_t CACHED_SEED[AREA_NUM]; 63 | 64 | void init_cached_structure_seed() { 65 | int index = 0; 66 | for (int i = -SEARCH_RADIUS; i <= SEARCH_RADIUS; i++) { 67 | for (int j = -SEARCH_RADIUS; j <= SEARCH_RADIUS; j++) { 68 | CACHED_SEED[index] = cal_candicate_seed(CENTER.x + i, CENTER.z + j); 69 | ++index; 70 | } 71 | } 72 | } 73 | } 74 | 75 | constexpr auto SEARCH_AREA = SearchArea(); 76 | 77 | 78 | bool in_range(int min, int max, int val) { 79 | return val >= min && val < max; 80 | } 81 | 82 | 83 | int get_cong_in_range(int begin, int modulo, int remain) { 84 | int r = begin - (begin % modulo); 85 | if (begin > 0) { 86 | r += modulo; 87 | } 88 | int c1 = r + remain; 89 | if (in_range(begin, begin + modulo, c1)) { 90 | return c1; 91 | } else { 92 | return c1 - modulo; 93 | } 94 | } 95 | 96 | 97 | uint64_t dis2(Pos p1, Pos p2) { 98 | int64_t dx = p1.x - p2.x; 99 | int64_t dz = p1.z - p2.z; 100 | return static_cast(dx * dx) + static_cast(dz * dz); 101 | } 102 | 103 | template 104 | Pos coord_map(const Pos &origin) { 105 | static_assert(SCALA > 0); 106 | auto cx = origin.x < 0 ? origin.x + 1 - SCALA : origin.x; 107 | auto cz = origin.z < 0 ? origin.z + 1 - SCALA : origin.z; 108 | return {cx / SCALA, cz / SCALA}; 109 | } 110 | 111 | 112 | template 113 | PosBox get_box(const Pos &origin) { 114 | auto x = origin.x * SCALA; 115 | auto z = origin.z * SCALA; 116 | return { 117 | {x, z}, 118 | {x + SCALA - 1, z + SCALA - 1} 119 | }; 120 | } 121 | 122 | //p是区域坐标 123 | template 124 | Pos get_candicate_structure_in_area(Pos areaPos, int spawn_range, Layer *layer, uint32_t seed, int index) { 125 | auto box = get_box(areaPos); 126 | const BEStructureConfig cfg = BE_OCEAN_MONUMENT; 127 | auto s_seed = CACHED_SEED[index] + seed; 128 | uint32_t *mt = mt_n_get(s_seed, 4); 129 | uint32_t r1 = mt[0] % cfg.spawnRange; 130 | uint32_t r2 = mt[1] % cfg.spawnRange; 131 | uint32_t r3 = mt[2] % cfg.spawnRange; 132 | uint32_t r4 = mt[3] % cfg.spawnRange; 133 | int avg_x = static_cast((r1 + r2) / 2); 134 | int avg_z = static_cast((r3 + r4) / 2); 135 | int i = get_cong_in_range(box.min.x, cfg.spacing, avg_x); 136 | int j = get_cong_in_range(box.min.z, cfg.spacing, avg_z); 137 | free(mt); 138 | return {i, j}; 139 | } 140 | 141 | template 142 | int check_seed(uint32_t seed, LayerStack *layerStack, int search_range, int dis, FILE *fp, int thread_idx) { 143 | int num = 0; 144 | if (fp == nullptr) { 145 | fp = stdout; 146 | } 147 | 148 | std::vector res; 149 | Layer *layer = &layerStack->layers[L_NUM - 2]; 150 | setLayerSeed(layer, seed); 151 | int w = (search_range << 1) + 1; 152 | const int area_num = w * w; 153 | auto *cp = new CandicateStructurePos[area_num]; 154 | int found_index = 0; 155 | auto poses = SEARCH_AREA.poses; 156 | for (int i = 0; i < area_num; i++) { 157 | auto pos = get_candicate_structure_in_area(poses[i], SPAWN_RANGE, layer, seed, i); 158 | cp[found_index].p = pos; 159 | cp[found_index].valid = -1; 160 | ++found_index; 161 | } 162 | 163 | const size_t max_dis_2 = dis * dis; 164 | for (int i = 0; i < found_index - 1; i++) { 165 | for (int j = i + 1; j < found_index; j++) { 166 | auto d2 = dis2(cp[i].p, cp[j].p); 167 | //距离合法 168 | if (d2 <= max_dis_2) { 169 | //如果第一个的群系还没有计算,就计算并缓存 170 | if (cp[i].valid == -1) { 171 | cp[i].valid = struct_position_valid(BEOceanMonument, layer, cp[i].p); 172 | } 173 | 174 | //算出来群系是对的 175 | if (cp[i].valid == 1) { 176 | //第二个的群系没有计算 177 | if (cp[j].valid == -1) { 178 | cp[j].valid = struct_position_valid(BEOceanMonument, layer, cp[j].p); 179 | } 180 | //如果第二个也满足 181 | if (cp[j].valid == 1) { 182 | ++num; 183 | PosBox box{}; 184 | box.min = cp[i].p; 185 | box.max = cp[j].p; 186 | res.push_back(box); 187 | if (d2 <= 36) { 188 | fprintf(fp, "seed: %u ([%d %d]-[%d %d] %.3f)\n", seed, 189 | cp[i].p.x * 16 + 8, cp[i].p.z * 16 + 8, 190 | cp[j].p.x * 16 + 8, cp[j].p.z * 16 + 8, 191 | 16 * sqrt(static_cast(d2)) 192 | ); 193 | } 194 | 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | free(cp); 202 | // if (res.size() >= 3) { 203 | // 204 | // if (res.size() > 3) { 205 | // printf("===============seed %u > 3=====================\n", seed); 206 | // } 207 | // std::set> pairs; 208 | // for (auto &i :res) { 209 | // pairs.insert({i.min.x, i.min.z}); 210 | // pairs.insert({i.max.x, i.max.z}); 211 | // //printf("[(%d %d)-(%d %d)]\n", i.min.x * 16 + 8, i.min.z * 16 + 8, i.max.x * 16 + 8, i.max.z * 16 + 8); 212 | // } 213 | // if (pairs.size() < 6 || res.size() > 3) { 214 | // printf("seed: %u\n", seed); 215 | // std::map, std::vector>> map; 216 | // for (auto &i :res) { 217 | // int x1 = i.min.x * 16 + 8; 218 | // int z1 = i.min.z * 16 + 8; 219 | // int x2 = i.max.x * 16 + 8; 220 | // int z2 = i.max.z * 16 + 8; 221 | // // printf("[(%d %d)-(%d %d) %.3f]\n", x1, z1, x2, z2, sqrt((double) dis2({x1, z1}, {x2, z2}))); 222 | // auto p1 = std::pair(x1, z1); 223 | // auto p2 = std::pair(x2, z2); 224 | // map[p1].push_back(p2); 225 | // map[p2].push_back(p1); 226 | // } 227 | // for (auto &p :map) { 228 | // if (p.second.size() >= 2) { 229 | // int x1 = p.second[0].first; 230 | // int z1 = p.second[0].second; 231 | // int x2 = p.second[1].first; 232 | // int z2 = p.second[1].second; 233 | // auto d = sqrt((double) dis2({x1, z1}, {x2, z2})); 234 | // if (d <= 280) { 235 | // printf("[%d %d] <==> [(%d %d)-(%d %d) %.3f]\n", p.first.first, p.first.second, 236 | // x1, z1, x2, z2, d); 237 | // } 238 | // } 239 | // 240 | // } 241 | // } 242 | // 243 | // 244 | // } 245 | return num; 246 | } 247 | 248 | 249 | void multi_finder(uint32_t seedMin, uint32_t seedMax) { 250 | size_t threadNum = std::thread::hardware_concurrency(); 251 | if (threadNum == 0) { 252 | fprintf(stderr, "the program can not decate the core num of this computer, 4 thread will be used\n"); 253 | threadNum = 4; 254 | } 255 | 256 | auto range = seedMax - seedMin + 1; 257 | auto length = range / threadNum; 258 | if (range % threadNum != 0) 259 | length++; 260 | std::vector threads; 261 | threads.reserve(threadNum); 262 | for (int i = 0; i < threadNum; ++i) { 263 | threads.emplace_back( 264 | [seedMax, seedMin, i, length, threadNum]() { 265 | uint32_t min = seedMin + i * length; 266 | uint32_t max = seedMin + (i + 1) * length - 1; 267 | if (i == threadNum - 1 && max != seedMax) 268 | max = seedMax; 269 | const size_t percent_1 = length / 100; 270 | printf("thread %d's range is :[%zu -- %zu]\n", i, min, max); 271 | LayerStack g; 272 | setupOverworldGenerator(&g, MC_1_17); 273 | const auto file_name = std::to_string(i) + ".txt"; 274 | FILE *fp = fopen(file_name.c_str(), "a+"); 275 | int index = 0; 276 | for (uint32_t s = min; s <= max; s++) { 277 | index++; 278 | if (index % percent_1 == 0) { 279 | printf("thread %d: %d%% finish\n", i, index / percent_1); 280 | } 281 | int n = check_seed<32, 26>(s, &g, SEARCH_RADIUS, 12, fp, i); 282 | } 283 | fclose(fp); 284 | printf("thread %d: finished\n", i); 285 | }); 286 | } 287 | 288 | 289 | for (auto &t:threads) { 290 | t.join(); 291 | } 292 | } 293 | 294 | -------------------------------------------------------------------------------- /backup/finder.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/20. 3 | // 4 | 5 | #ifndef CUBIOMES_FINDER_H 6 | #define CUBIOMES_FINDER_H 7 | 8 | typedef int i1; 9 | 10 | #include 11 | #include "structure.h" 12 | 13 | struct PosBox { 14 | Pos min; 15 | Pos max; 16 | friend std::ostream &operator<<(std::ostream &os, const PosBox &box) { 17 | os << "min: " << box.min.x << " " << box.min.z << " max: " << box.max.x << " " << box.max.z; 18 | return os; 19 | } 20 | }; 21 | 22 | 23 | #endif //CUBIOMES_FINDER_H 24 | 25 | -------------------------------------------------------------------------------- /backup/main.cpp: -------------------------------------------------------------------------------- 1 | #include "finder.h" 2 | #include "utils.h" 3 | #include "finder.h" 4 | 5 | int main(int argc, const char *argv[]) { 6 | // if (argc != 3) { 7 | // fprintf(stderr, "use ./find [minseed] [maxseed]"); 8 | // return -1; 9 | // } 10 | // uint32_t min = std::strtoul(argv[1], nullptr, 10); 11 | // uint32_t max = std::strtoul(argv[2], nullptr, 10); 12 | // if (min >= max) { 13 | // 14 | // fprintf(stderr, "use ./find [minseed] [maxseed]"); 15 | // return -1; 16 | // } 17 | // printf("search range is[%u -- %u]", min, max); 18 | // init_cached_structure_seed(); 19 | // TIMER_START 20 | // multi_finder(min, max); 21 | // TIMER_END 22 | // printf("%.3lfs used\n", static_cast(timeReslut) / 1000000.0); 23 | 24 | // init_cached_structure_seed(); 25 | // LayerStack g; 26 | // setupOverworldGenerator(&g, MC_1_17); 27 | // std::ifstream fin("p3.txt"); 28 | // std::string s; 29 | // while (!fin.eof()) { 30 | // getline(fin, s); 31 | // uint32_t seed = std::strtoul(s.c_str(), nullptr, 10); 32 | // check_seed<32, 26>(seed, &g, SEARCH_RADIUS, 12, nullptr, 0); 33 | // } 34 | StructureFinder finder({0, 0}, 2000, BE_OCEAN_MONUMENT); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /backup/result/ocean_monument/(Pseudo) Triple.txt: -------------------------------------------------------------------------------- 1 | 1938075687 [-1144 -632] <==> [(-1160 -472)-(-1000 -680) 262.420] 2 | 2221315309 [1384 1064] <==> [(1368 920)-(1576 1064) 252.982] 3 | 2366329760 [72 -504] <==> [(-104 -504)-(120 -664) 275.274] -------------------------------------------------------------------------------- /backup/result/ocean_monument/Double(96 blocks distance).txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedrock-dev/MCBEStructureFinder/14d79b8c92f6d67d1e4556e535b8babef3cc91b9/backup/result/ocean_monument/Double(96 blocks distance).txt -------------------------------------------------------------------------------- /backup/result/ocean_monument/README.md: -------------------------------------------------------------------------------- 1 | We serached all seed(0 to 2^32-1) with the area xz in (-2304,2304) and get the 2 | seeds which include double or triple ocean monuments. 3 | 4 | Notice: 5 | There is no guarantee that all spawn points can be ticking in triple -------------------------------------------------------------------------------- /backup/test/test_base.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #define TEST namespace {std::vector> tests;} 8 | 9 | #define ADD_TEST(F_CALL) tests.emplace_back([](){F_CALL;}) 10 | 11 | #define RUN_ALL_TEST for(auto &t:tests)t(); 12 | 13 | 14 | #define EXPECT_TRUE(val) assert(val) 15 | #define EXPECT_FALSE(val) assert(!(val)) 16 | 17 | #define EXPECT_EQ(x, y) assert((x) == (y)) 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /backup/test/utils_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/23. 3 | // 4 | #include 5 | #include "utils.h" 6 | #include "test_base.h" 7 | #include 8 | 9 | void test_between() { 10 | EXPECT_TRUE(between(0, 12, 3)); 11 | EXPECT_TRUE(between(0, 1, 0)); 12 | EXPECT_TRUE(between(0, 1, 1)); 13 | EXPECT_FALSE(between(0, 4, -1)); 14 | } 15 | 16 | void test_scala_down() { 17 | auto p = scala_down({15, 15}, 16); 18 | auto p_1 = Vec2i{0, 0}; 19 | EXPECT_EQ(p, p_1); 20 | auto p2 = scala_down({16, 15}, 16); 21 | auto p2_1 = Vec2i{1, 0}; 22 | EXPECT_EQ(p2, p2_1); 23 | auto p3 = scala_down({-16, -16}, 16); 24 | auto p3_1 = Vec2i{-1, -1}; 25 | EXPECT_EQ(p3, p3_1); 26 | auto p4 = scala_down({-17, -17}, 16); 27 | auto p4_1 = Vec2i{-2, -2}; 28 | EXPECT_EQ(p4, p4_1); 29 | } 30 | 31 | void test_scala_up() { 32 | auto p = Vec2i{0, 0}; 33 | auto box = scala_up(p, 16); 34 | auto min = Vec2i{0, 0}, max = Vec2i{15, 15}; 35 | EXPECT_EQ(box.min, min); 36 | EXPECT_EQ(box.max, max); 37 | p = Vec2i{-1, -1}; 38 | box = scala_up(p, 32); 39 | min = {-32, -32}; 40 | max = {-1, -1}; 41 | EXPECT_EQ(box.min, min); 42 | EXPECT_EQ(box.max, max); 43 | } 44 | 45 | 46 | void test_get_cong_in_range() { 47 | EXPECT_EQ(get_cong_with_module(0, 12, 1), 1); 48 | EXPECT_EQ(get_cong_with_module(2, 2, 3), 3); 49 | EXPECT_EQ(get_cong_with_module(-12, 7, 3), -4); 50 | EXPECT_EQ(get_cong_with_module(-1, 1, 1), 0); 51 | } 52 | 53 | void test_log() { 54 | int a = 12; 55 | LOG("the value of a is %d", a); 56 | } 57 | 58 | 59 | int main() { 60 | test_between(); 61 | test_scala_down(); 62 | test_scala_up(); 63 | test_log(); 64 | 65 | return 0; 66 | } -------------------------------------------------------------------------------- /backup/utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/23. 3 | // 4 | 5 | #include "utils.h" 6 | #include 7 | #include 8 | 9 | bool Vec2i::operator<(const Vec2i &rhs) const { 10 | if (x < rhs.x) 11 | return true; 12 | if (rhs.x < x) 13 | return false; 14 | return z < rhs.z; 15 | } 16 | 17 | bool Vec2i::operator==(const Vec2i &rhs) const { 18 | return x == rhs.x && 19 | z == rhs.z; 20 | } 21 | 22 | bool Box::operator<(const Box &rhs) const { 23 | if (min < rhs.min) 24 | return true; 25 | if (rhs.min < min) 26 | return false; 27 | return max < rhs.max; 28 | } 29 | 30 | bool Box::operator==(const Box &rhs) const { 31 | return min == rhs.min && 32 | max == rhs.max; 33 | } 34 | 35 | void log(const char *file_name, const char *function_name, size_t line, const char *fmt, ...) { 36 | #ifdef DEBUG 37 | va_list args; 38 | va_start(args, fmt); 39 | printf("<%s> [%s: %d] ", file_name, function_name, line); 40 | vprintf(fmt, args); 41 | printf("\n"); 42 | #endif 43 | } 44 | -------------------------------------------------------------------------------- /backup/utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/23. 3 | // 4 | 5 | #ifndef CUBIOMES_UTILS_H 6 | #define CUBIOMES_UTILS_H 7 | 8 | #include 9 | #include 10 | 11 | #define DEBUG 12 | #ifdef WIN32 13 | #define __FILENAME__ (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__) 14 | #elif 15 | #define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) 16 | #endif 17 | #define LOG(fmt, ...) log(__FILENAME__,__FUNCTION__,__LINE__,fmt,__VA_ARGS__) 18 | 19 | typedef std::chrono::high_resolution_clock timer_clock; 20 | #define TIMER_START auto start = timer_clock::now(); 21 | #define TIMER_END \ 22 | auto elapsed = timer_clock::now() - start; \ 23 | long long timeReslut = \ 24 | std::chrono::duration_cast(elapsed) \ 25 | .count(); 26 | 27 | struct Vec2i { 28 | int x = 0; 29 | int z = 0; 30 | 31 | bool operator<(const Vec2i &rhs) const; 32 | 33 | bool operator==(const Vec2i &rhs) const; 34 | 35 | constexpr Vec2i(int xx, int zz) : x(xx), z(zz) {} 36 | 37 | 38 | Vec2i operator+(const Vec2i &rhs) const { 39 | return {x + rhs.x, z + rhs.z}; 40 | } 41 | 42 | Vec2i operator-(const Vec2i &rhs) const { 43 | return {x - rhs.x, z - rhs.z}; 44 | } 45 | 46 | 47 | Vec2i() = default; 48 | }; 49 | 50 | struct Box { 51 | Vec2i min; 52 | Vec2i max; 53 | 54 | bool operator<(const Box &rhs) const; 55 | 56 | bool operator==(const Box &rhs) const; 57 | }; 58 | 59 | typedef Vec2i ChunkPos; 60 | typedef Vec2i Pos; 61 | 62 | template 63 | inline bool between(const T &min, const T &max, const T &x) { 64 | return x >= min && x <= max; 65 | } 66 | 67 | inline Pos scala_down(const Vec2i &origin, int SCALA) { 68 | auto cx = origin.x < 0 ? origin.x + 1 - SCALA : origin.x; 69 | auto cz = origin.z < 0 ? origin.z + 1 - SCALA : origin.z; 70 | return {cx / SCALA, cz / SCALA}; 71 | } 72 | 73 | inline Box scala_up(const Pos &origin, int SCALA) { 74 | auto x = origin.x * SCALA; 75 | auto z = origin.z * SCALA; 76 | return { 77 | {x, z}, 78 | {x + SCALA - 1, z + SCALA - 1} 79 | }; 80 | } 81 | 82 | //get the fisrt number(>= begin) which === remain (mod module) 83 | //返回区间[begin,+inf)中和remain同余的最小的数(模modulo) 84 | inline int get_cong_with_module(int begin, int modulo, int remain) { 85 | int r = begin - (begin % modulo); 86 | if (begin > 0) 87 | r += modulo; 88 | auto c1 = r + remain; 89 | return between(begin, begin + modulo, c1) ? c1 : c1 - modulo; 90 | } 91 | 92 | 93 | void log(const char *file_name, const char *function_name, size_t line, const char *fmt, ...); 94 | 95 | #endif //CUBIOMES_UTILS_H 96 | -------------------------------------------------------------------------------- /be_finder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/23. 3 | // 4 | #include "be_finder.h" 5 | #include 6 | #include 7 | #include "be_random.h" 8 | #include 9 | 10 | namespace { 11 | uint32_t cal_candicate_seed(const Vec2i &p, int salt) { 12 | return salt - 245998635 * p.z - 1724254968 * p.x; 13 | } 14 | } 15 | 16 | StructureFinder::StructureFinder(const Pos &search_center, size_t range, BEStructureConfig config) { 17 | //init search center 18 | //先转成区块坐标 19 | auto chunk_pos_center = scala_down(search_center, 16); 20 | //再转成区域坐标 21 | this->center_ = scala_down(chunk_pos_center, config.spacing); 22 | this->config_ = config; 23 | LOG("search center's area position is[%d,%d]", center_.x, center_.z); 24 | LOG("structure config is:\nSpacing: [%d]Spawn range: [%d] Salt: [%d]", config_.spacing, 25 | config_.spawnRange, 26 | config_.salt); 27 | 28 | int area_width = this->config_.spacing * 16; 29 | LOG("area width is %d", area_width); 30 | radius_ = static_cast(range) / area_width; 31 | if (range % config.spacing != 0) 32 | ++radius_; 33 | --radius_; 34 | LOG("serach radius is %d", radius_); 35 | for (int i = -radius_; i <= radius_; i++) { 36 | for (int j = -radius_; j <= radius_; j++) { 37 | Vec2i area_pos = {this->center_.x + i, this->center_.z + j}; 38 | areas_.emplace_back(area_pos, cal_candicate_seed(area_pos, config_.salt)); 39 | } 40 | } 41 | 42 | auto min_chunk = scala_up(areas_[0].area_pos, this->config_.spacing).min; 43 | auto max_chunk = scala_up(areas_[areas_.size() - 1].area_pos, config_.spacing).max; 44 | auto min_pos = scala_up(min_chunk, 16).min; 45 | auto max_pos = scala_up(max_chunk, 16).max; 46 | 47 | LOG("total %zu areas need search, range is [%d %d] -- [%d %d]", areas_.size(), min_pos.x, min_pos.z, 48 | max_pos.x, max_pos.z); 49 | } 50 | 51 | 52 | std::vector StructureFinder::get_candicate_positions(uint32_t seed) { 53 | std::vector p; 54 | for (auto &area: this->areas_) { 55 | auto pos = get_candicate_pos_in_area(area.area_pos, area.candicate_area_seed + seed); 56 | p.push_back(pos); 57 | } 58 | return p; 59 | } 60 | 61 | Pos StructureFinder::get_candicate_pos_in_area(const AreaPos &p, uint32_t area_seed) const { 62 | assert(config_.num == 2 || config_.num == 4); 63 | auto box = scala_up(p, config_.spacing); 64 | uint32_t *mt = mt_n_get(area_seed, config_.num); 65 | uint32_t r1 = mt[0] % config_.spawnRange; 66 | uint32_t r2 = mt[1] % config_.spawnRange; 67 | uint32_t avg_x, avg_z; 68 | if (config_.num == 2) { 69 | avg_x = r1; 70 | avg_z = r2; 71 | } else { 72 | uint32_t r3 = mt[2] % config_.spawnRange; 73 | uint32_t r4 = mt[3] % config_.spawnRange; 74 | avg_x = static_cast((r1 + r2) / 2); 75 | avg_z = static_cast((r3 + r4) / 2); 76 | } 77 | int i = get_cong_with_module(box.min.x, config_.spacing, avg_x); 78 | int j = get_cong_with_module(box.min.z, config_.spacing, avg_z); 79 | return {i, j}; 80 | } 81 | -------------------------------------------------------------------------------- /be_finder.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/23. 3 | // 4 | 5 | #ifndef CUBIOMES_NEW_FINDER_H 6 | #define CUBIOMES_NEW_FINDER_H 7 | 8 | #include 9 | 10 | #include "structure.h" 11 | 12 | struct CachedArea { 13 | Vec2i area_pos; 14 | uint32_t candicate_area_seed = 0; 15 | 16 | CachedArea(const Vec2i &p, uint32_t seed) : area_pos(p), candicate_area_seed(seed) {} 17 | }; 18 | 19 | 20 | class StructureFinder { 21 | private: 22 | Pos center_{}; 23 | int radius_{}; 24 | BEStructureConfig config_{}; 25 | std::vector areas_; 26 | 27 | Pos get_candicate_pos_in_area(const Pos &p, uint32_t area_seed) const; 28 | 29 | public: 30 | /** 31 | * 结构查找器的输入 32 | * @param search_center 输入中心(方块坐标) 33 | * @param range 输入半径 34 | * @param config 结构参数数据 35 | */ 36 | StructureFinder(const Pos &search_center, size_t range, BEStructureConfig config); 37 | 38 | StructureFinder() = delete; 39 | 40 | std::vector get_candicate_positions(uint32_t seed); 41 | }; 42 | 43 | 44 | #endif //CUBIOMES_NEW_FINDER_H 45 | -------------------------------------------------------------------------------- /be_random.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/3. 3 | // 4 | 5 | #include "be_random.h" 6 | #include 7 | 8 | 9 | #define INIT(L, R, OFF) L = 0x6c078965 * ((R) ^ (R >> 30u)) + (OFF) 10 | 11 | uint32_t *mt_n_get(uint32_t seed, int n) { 12 | //uint32_t *head_arr = (uint32_t *) malloc(sizeof(uint32_t) * (n + 1)); 13 | auto *head_arr = new uint32_t[n + 1]; 14 | auto *last_arr = new uint32_t[n + 1]; 15 | auto *result = new uint32_t[n]; 16 | head_arr[0] = seed; 17 | for (int i = 1; i < n + 1; i++) 18 | INIT(head_arr[i], head_arr[i - 1], i); 19 | uint32_t temp = head_arr[n]; 20 | for (int i = n; i < 397; i++) 21 | INIT(temp, temp, i + 1); 22 | last_arr[0] = temp; 23 | for (int i = 1; i < n + 1; ++i) 24 | INIT(last_arr[i], last_arr[i - 1], i + 397); 25 | for (int i = 0; i < n; i++) { 26 | temp = (head_arr[i] & 0x80000000) + (head_arr[i + 1] & 0x7fffffffu); 27 | head_arr[i] = (temp >> 1u) ^ last_arr[i]; 28 | if (temp % 2 != 0) 29 | head_arr[i] = head_arr[i] ^ 0x9908b0df; 30 | } 31 | for (int i = 0; i < n; 32 | ++i) { 33 | uint32_t y = head_arr[i]; 34 | y = y ^ y >> 11u; 35 | y = y ^ y << 7u & 2636928640u; 36 | y = y ^ y << 15u & 4022730752u; 37 | y = y ^ y >> 18u; 38 | result[i] = y; 39 | } 40 | free(head_arr); 41 | free(last_arr); 42 | return result; 43 | } 44 | 45 | float int_2_float(uint32_t x) { 46 | return static_cast(x) * 2.328306436538696e-10f; 47 | } -------------------------------------------------------------------------------- /be_random.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/3. 3 | // 4 | 5 | #ifndef BSSTRUCTURRE_BEDRNG_H 6 | #define BSSTRUCTURRE_BEDRNG_H 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | 14 | uint32_t *mt4_get(uint32_t seed); 15 | 16 | uint32_t *mt2_get(uint32_t seed); 17 | 18 | uint32_t *mt_n_get(uint32_t seed, int n); 19 | 20 | float int_2_float(uint32_t); 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | #endif //BSSTRUCTURRE_BEDRNG_H 25 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/12/16. 3 | // 4 | #include "be_finder.h" 5 | #include "structure.h" 6 | #include "tools.h" 7 | #include 8 | 9 | int main() { 10 | // Generator g; 11 | 12 | // setupGenerator(&g, MC_1_18, 0); 13 | // uint64_t seed = 123LL; 14 | // applySeed(&g, 0, seed); 15 | // const Pos center = {5384, 15608}; 16 | // StructureFinder finder(center, 1000, BE_RANDOM_SCATTERED); 17 | // auto p_list = finder.get_candicate_positions(seed); 18 | // for (auto p : p_list) { 19 | // if (extra_feature_check(&g, BEWitchHut, p)) { 20 | // LOG("%d %d", p.x * 16 + 8, p.z * 16 + 8); 21 | // } 22 | // } 23 | auto pos = get_world_spawn_position(123); 24 | LOG("%d %d", pos.x, pos.z); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /structure.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/3. 3 | // 4 | 5 | #include "structure.h" 6 | #include 7 | 8 | #include "be_random.h" 9 | #include "generator.h" 10 | #include "layers.h" 11 | #include "util.h" 12 | #include 13 | #include 14 | 15 | namespace { 16 | int max(int x, int z) { return x < z ? z : x; } 17 | 18 | int find_in_filter(BiomeID target, const BiomeID biomes[], size_t n) { 19 | for (int i = 0; i < n; i++) { 20 | if (target == biomes[i]) { 21 | return 1; 22 | } 23 | } 24 | return 0; 25 | } 26 | } // namespace 27 | 28 | static bool area_contain_biome_only(struct Generator *g, int px, int pz, int r, 29 | const BiomeID filter[], size_t n) { 30 | if (!g) 31 | return false; 32 | // use a 4*4 resolution to check 33 | int x0 = (px - r) >> 2; 34 | int z0 = (pz - r) >> 2; 35 | int w = ((r + px) >> 2) - x0 + 1; 36 | int h = ((r + pz) >> 2) - z0 + 1; 37 | struct Range range {}; 38 | // 1:16, a.k.a. horizontal chunk scaling 39 | range.scale = 4; 40 | // Define the position and size for a horizontal area: 41 | range.x = x0; //中心x 42 | range.z = z0; //中心x 43 | range.sx = w, range.sz = h; // size (width,height) 44 | // Set the vertical range as a plane near sea level at scale 1:4. 45 | range.y = 15, range.sy = 1; 46 | int *biomeIds = allocCache(g, range); 47 | genBiomes(g, biomeIds, range); 48 | 49 | // int pix4cell = 4; 50 | // int imgWidth = pix4cell * range.sx, imgHeight = pix4cell * range.sz; 51 | // unsigned char biomeColors[256][3]; 52 | // initBiomeColors(biomeColors); 53 | // auto *rgb = (unsigned char *)malloc(3 * imgWidth * imgHeight); 54 | // biomesToImage(rgb, biomeColors, biomeIds, range.sx, range.sz, pix4cell, 55 | // 2); 56 | 57 | // // Save the RGB buffer to a PPM image file. 58 | // auto name = "map-" + std::to_string(px) + "-" + std::to_string(pz) + 59 | // ".ppm"; savePPM(name.c_str(), rgb, imgWidth, imgHeight); 60 | 61 | const int area = w * h; 62 | for (int i = 0; i < area; i++) { 63 | if (!find_in_filter(static_cast(biomeIds[i]), filter, n)) { 64 | free(biomeIds); 65 | return false; 66 | } 67 | } 68 | free(biomeIds); 69 | return true; 70 | } 71 | 72 | int is_valid_spawn_biome(int biome_id) { 73 | return find_in_filter(static_cast(biome_id), WORLD_SPAWN_FILTER, 74 | sizeof(WORLD_SPAWN_FILTER) / BSZ); 75 | } 76 | 77 | // thanks for ddf 78 | // There is an error within tens of meters 79 | Vec2i get_world_spawn_position(uint32_t seed) { 80 | LayerStack g; 81 | // setupOverworldGenerator(&g, MC_1_17); 82 | Layer *layer = &g.layers[L_NUM - 2]; 83 | setLayerSeed(layer, seed); 84 | Vec2i pos{-1, -1}; 85 | int step = 0; 86 | while (true) { 87 | int *biomeIds = nullptr; 88 | 89 | // allocCache(layer, 10, 10); 90 | genArea(layer, biomeIds, step, 0, 10, 10); 91 | for (int zo = 0; zo < 10; zo++) { 92 | for (int xo = 0; xo < 10; xo++) { 93 | int v7 = biomeIds[xo + 10 * zo]; 94 | if (is_valid_spawn_biome(v7)) { 95 | if (xo) { 96 | int v6 = biomeIds[(xo - 1) + 10 * zo]; 97 | if (is_valid_spawn_biome(v6) && xo + 1 < 10) { 98 | int v5 = biomeIds[(xo + 1) + 10 * zo]; 99 | if (is_valid_spawn_biome(v5)) { 100 | if (zo) { 101 | int v4 = biomeIds[xo * 10 * (zo - 1)]; 102 | if (is_valid_spawn_biome(v4) && zo + 1 < 10) { 103 | int v3 = biomeIds[xo * 10 * (zo + 1)]; 104 | if (is_valid_spawn_biome(v3)) { 105 | pos.x = 4 * (xo + step); 106 | pos.z = zo * 4; 107 | return pos; 108 | } 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | step += 10; 118 | free(biomeIds); 119 | } 120 | } 121 | 122 | static int check_ship_wreak() { return 1; } 123 | 124 | static int check_ocean_ruin() { return 1; } 125 | 126 | static bool check_random_scattered(Generator *g, enum BEStructureType type, 127 | ChunkPos pos) { 128 | int x = pos.x * 16 + 8; 129 | int z = pos.z * 16 + 8; 130 | switch (type) { 131 | case BEDesertTemple: 132 | return area_contain_biome_only(g, x, z, 0, DESERT_TEMPLE_FILTER, 2); 133 | case BEJungleTemple: 134 | return area_contain_biome_only(g, x, z, 0, JUNGLE_TEMPLE_FILTER, 2); 135 | case BEWitchHut: 136 | return area_contain_biome_only(g, x, z, 0, WITCH_HUT_FILTER, 2); 137 | case BEIgloo: 138 | return area_contain_biome_only(g, x, z, 0, IGLOO_FILTER, 2); 139 | default: 140 | return 0; 141 | } 142 | } 143 | 144 | static int check_ruined_portal() { return 1; } 145 | 146 | // error 147 | static int check_minshaft(uint32_t seed, ChunkPos pos) { 148 | uint32_t *mt = mt_n_get(seed, 2); 149 | uint32_t chunk_seed = seed ^ (mt[1] * pos.z) ^ (mt[0] * pos.x); 150 | uint32_t *mt2 = mt_n_get(chunk_seed, 3); 151 | double rf = int_2_float(mt2[1]); 152 | if (rf >= 0.004) 153 | return 0; 154 | return mt2[2] % 80 < max(abs(pos.x), abs(pos.z)); 155 | } 156 | 157 | static bool struct_position_valid(struct Generator *g, 158 | enum BEStructureType type, ChunkPos pos) { 159 | int x = pos.x * 16 + 8; 160 | int z = pos.z * 16 + 8; 161 | switch (type) { 162 | case BEVillage: 163 | return area_contain_biome_only(g, x, z, 2, VILLAGE_FILTER, 164 | sizeof(VILLAGE_FILTER) / BSZ); 165 | case BEOceanMonument: 166 | if (!area_contain_biome_only(g, x, z, 16, OCEAN_MONUMENT_SPAWN_FILTER, 167 | sizeof(OCEAN_MONUMENT_SPAWN_FILTER) / BSZ)) { 168 | return 0; 169 | } else { 170 | return area_contain_biome_only(g, x, z, 29, OCEAN_MONUMENT_FILTER, 171 | sizeof(OCEAN_MONUMENT_FILTER) / BSZ); 172 | } 173 | case BEBuriedTreasure: 174 | return area_contain_biome_only(g, x, z, 3, BURIED_TREASURE_FILTER, 175 | sizeof(BURIED_TREASURE_FILTER) / BSZ); 176 | case BEWoodlandMansion: 177 | return area_contain_biome_only(g, x, z, 32, WOODLAND_MANSION_FILTER, 178 | sizeof(WOODLAND_MANSION_FILTER) / BSZ); 179 | case BEPillagerOutpost: 180 | return area_contain_biome_only(g, x, z, 0, PILLAGER_OUTPOST_FILTER, 181 | sizeof(PILLAGER_OUTPOST_FILTER) / BSZ); 182 | default: 183 | break; 184 | } 185 | return 1; 186 | } 187 | 188 | // int is_feature_chunk_nether(enum BEStructureType type, Layer *layer, 189 | 190 | // uint32_t worldSeed, ChunkPos chunkPos) { 191 | // if (type == BERuindPortal) { 192 | // return structure_location_check_2(BE_RUIN_PORTAL_NETHER, worldSeed, 193 | // chunkPos); 194 | // } 195 | // if (type != BEBastion && type != BENetherFortress) { 196 | // return 0; 197 | // } 198 | // struct BEStructureConfig cfg = BE_NETHER_STRUCTURE; 199 | // if (chunkPos.x < 0) 200 | // chunkPos.x -= cfg.spacing - 1; 201 | // if (chunkPos.z < 0) 202 | // chunkPos.z -= cfg.spacing - 1; 203 | // uint32_t seed = cal_structure_seed( 204 | // worldSeed, cfg.salt, chunkPos.x / cfg.spacing, chunkPos.z / 205 | // cfg.spacing); 206 | 207 | // uint32_t *mt = mt_n_get(seed, 3); 208 | // uint32_t r1 = mt[0] % cfg.spawnRange; 209 | // uint32_t r2 = mt[1] % cfg.spawnRange; 210 | // int xOff = chunkPos.x % cfg.spacing; 211 | // int zOff = chunkPos.z % cfg.spacing; 212 | // if (xOff < 0) 213 | // xOff += cfg.spacing - 1; 214 | // if (zOff < 0) 215 | // zOff += cfg.spacing - 1; 216 | // if (r1 == xOff && r2 == zOff) { 217 | // if (mt[2] % 6 >= 2) { 218 | // free(mt); 219 | // return BEBastion; 220 | // } else { 221 | // free(mt); 222 | // return BENetherFortress; 223 | // } 224 | // } else { 225 | // free(mt); 226 | // return 0; 227 | // } 228 | // } 229 | 230 | bool extra_feature_check(struct Generator *g, enum BEStructureType type, 231 | ChunkPos pos) { 232 | if (type == BEJungleTemple || type == BEDesertTemple || type == BEWitchHut || 233 | type == BEIgloo) { 234 | return check_random_scattered(g, type, pos); 235 | } else if (type == BEOceanMonument || type == BEVillage || 236 | type == BEOceanRuin || type == BEWoodlandMansion || 237 | type == BEBuriedTreasure || type == BEPillagerOutpost) { 238 | return struct_position_valid(g, type, pos); 239 | } else { 240 | // todo 241 | switch (type) { 242 | case BERuindPortal: 243 | return true; 244 | case BEStronghold: 245 | return false; 246 | case BEMineshaft: 247 | return check_minshaft(0, pos); 248 | case BEShipwreck: 249 | return check_ship_wreak(); 250 | case BEEndcity: 251 | return false; 252 | } 253 | } 254 | return true; 255 | } 256 | 257 | ChunkPos *generate_stronghold_positions(uint32_t seed, struct Layer *layer) { 258 | auto *positions = new ChunkPos[3]; 259 | uint32_t *mt = mt_n_get(seed, 2); 260 | int count = 0; 261 | double angle = 6.2831855 * int_2_float(mt[0]); 262 | uint32_t chunk_dist = mt[1] % 16 + 40; 263 | while (count < 3) { 264 | double cos_v = cos(angle); 265 | int cx = floor(cos_v * chunk_dist); 266 | double sin_v = sin(angle); 267 | int cz = floor(sin_v * chunk_dist); 268 | int found = 0; 269 | for (int chunkX = cx - 8; chunkX < cx + 8; ++chunkX) { 270 | for (int chunkZ = cz - 8; chunkZ < cz + 8; ++chunkZ) { 271 | // village near 272 | ChunkPos pos = {chunkX, chunkZ}; 273 | //这儿需要重写先不管 274 | // if (is_feature_chunk_overworld(BEVillage, layer, seed, pos)) { 275 | found = 1; 276 | positions[count].x = chunkX * 16; 277 | positions[count].z = chunkZ * 16; 278 | ++count; 279 | if (count == 3) { 280 | return positions; 281 | } 282 | break; 283 | } 284 | 285 | // } 286 | } 287 | if (found) { 288 | angle += 1.8849558; 289 | chunk_dist += 8; 290 | } else { 291 | angle += 0.78539819; 292 | chunk_dist += 4; 293 | } 294 | } 295 | return positions; 296 | } 297 | 298 | BiomeID get_biome_at_pos(Layer *layer, int x, int z) { 299 | int *ids = nullptr; 300 | // allocCache(layer, 1, 1); 301 | genArea(layer, ids, x, z, 1, 1); 302 | auto biomeID = static_cast(ids[0]); 303 | free(ids); 304 | return biomeID; 305 | } 306 | 307 | int check_nether_fortress_1_14(uint32_t worldseed, ChunkPos pos) { 308 | int cx = pos.x >> 4; 309 | int cz = pos.z >> 4; 310 | uint32_t seed = worldseed ^ (cz << 4) ^ cx; 311 | uint32_t *mt = mt_n_get(seed, 4); 312 | if (mt[1] % 3 != 0) { 313 | return 0; 314 | } 315 | return pos.x == mt[2] % 8 + 16 * cx + 4 && pos.z == mt[3] % 8 + 16 + cz + 4; 316 | } 317 | -------------------------------------------------------------------------------- /structure.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/8/3. 3 | // 4 | 5 | #pragma once 6 | #ifndef BSSTRUCTURRE_STRUCTURE_H 7 | #define BSSTRUCTURRE_STRUCTURE_H 8 | 9 | #endif // BSSTRUCTURRE_STRUCTURE_H 10 | 11 | #include "generator.h" 12 | #include "layers.h" 13 | #include "tools.h" 14 | 15 | enum BEStructureType { 16 | BEVillage, 17 | BEStronghold, 18 | BEMineshaft, 19 | BEDesertTemple, 20 | BEWitchHut, 21 | BEJungleTemple, 22 | BEIgloo, 23 | BEOceanMonument, 24 | BEOceanRuin, 25 | BEWoodlandMansion, 26 | BEShipwreck, 27 | BERuindPortal, 28 | BEBuriedTreasure, 29 | BEPillagerOutpost, 30 | BENetherFortress, 31 | BEBastion, 32 | BEEndcity 33 | }; 34 | 35 | int check_nether_fortress_1_14(uint32_t worldseed, ChunkPos pos); 36 | 37 | struct BEStructureConfig { 38 | int spacing; 39 | int spawnRange; 40 | int salt; 41 | int num; 42 | }; 43 | 44 | #define DEF_STRUCTURE(Name, spacing, spawnRange, salt) \ 45 | constexpr BEStructureConfig Name = {spacing, spawnRange, salt}; 46 | 47 | constexpr BEStructureConfig BE_RANDOM_SCATTERED = { 48 | 32, 24, 14357617, 2}; //女巫房子,丛林,沙漠神殿 49 | constexpr BEStructureConfig BE_BURIED_TREASURE = {4, 2, 16842397, 4}; //海底宝藏 50 | constexpr BEStructureConfig BE_PILLAGER_OUTPOST = {80, 56, 165745296, 4}; //哨塔 51 | constexpr BEStructureConfig BE_VILLAGE = {27, 17, 10387312, 4}; //村庄 52 | constexpr BEStructureConfig BE_WOODLAND_MANSION = {80, 60, 10387319, 53 | 4}; //林地府邸 54 | constexpr BEStructureConfig BE_END_CITY = {20, 9, 10387313, 4}; //末地城市 55 | constexpr BEStructureConfig BE_OCEAN_MONUMENT = {32, 27, 10387313, 56 | 4}; //海底神殿 57 | constexpr BEStructureConfig BE_NETHER_STRUCTURE = {30, 26, 430084232, 4}; 58 | constexpr BEStructureConfig BE_SHIP_WREAK = {10, 5, 1, 4}; 59 | constexpr BEStructureConfig BE_OCEAN_RUIN = {12, 5, 14357621, 4}; 60 | constexpr BEStructureConfig BE_RUIN_PORTAL_NETHER = {25, 15, 40552231, 4}; 61 | constexpr BEStructureConfig BE_RUIN_PORTAL_OVERWORLD = {40, 25, 40552231, 4}; 62 | constexpr BEStructureConfig BE_INVALID = {1, 1, 0, 1}; 63 | 64 | void biome_test(uint32_t seed, int l, const char *path, int width); 65 | 66 | constexpr uint16_t BSZ = sizeof(enum BiomeID); 67 | 68 | constexpr enum BiomeID WORLD_SPAWN_FILTER[] = { 69 | forest, plains, taiga_hills, forestHills, jungle_hills, jungle}; 70 | 71 | constexpr enum BiomeID VILLAGE_FILTER[] = { 72 | plains, savanna, icePlains, taiga, 73 | taiga_hills, coldTaiga, coldTaigaHills, desert}; 74 | 75 | constexpr enum BiomeID OCEAN_MONUMENT_FILTER[] = {ocean, 76 | deep_ocean, 77 | lukewarm_ocean, 78 | cold_ocean, 79 | frozen_ocean, 80 | warm_ocean, 81 | 82 | deep_lukewarm_ocean, 83 | deep_warm_ocean, 84 | deep_frozen_ocean, 85 | deep_cold_ocean, 86 | 87 | river, 88 | frozen_river}; 89 | 90 | constexpr enum BiomeID OCEAN_MONUMENT_SPAWN_FILTER[] = { 91 | deep_ocean, deep_cold_ocean, deep_warm_ocean, deep_frozen_ocean, 92 | deep_lukewarm_ocean}; 93 | 94 | constexpr enum BiomeID DESERT_TEMPLE_FILTER[] = {desert, desert_hills, 95 | desert_lakes}; 96 | 97 | constexpr enum BiomeID JUNGLE_TEMPLE_FILTER[] = {jungle, jungle_hills}; 98 | constexpr enum BiomeID WITCH_HUT_FILTER[] = {swamp, swampland}; 99 | constexpr enum BiomeID IGLOO_FILTER[] = {icePlains, coldTaiga}; 100 | // NOT 101 | constexpr enum BiomeID BURIED_TREASURE_FILTER[] = { 102 | beach, coldBeach, stone_shore, mushroom_field_shore}; 103 | 104 | constexpr enum BiomeID WOODLAND_MANSION_FILTER[] = {roofedForest}; 105 | 106 | constexpr enum BiomeID PILLAGER_OUTPOST_FILTER[] = { 107 | plains, sunflower_plains, savanna, icePlains, taiga_hills, 108 | taiga, coldTaiga, coldTaigaHills, desert}; 109 | 110 | // extra check for structure 111 | bool extra_feature_check(struct Generator *g, enum BEStructureType type, 112 | ChunkPos pos); 113 | 114 | // get the first 3 position of stronghold 115 | ChunkPos *generate_stronghold_positions(uint32_t seed, struct Layer *layer); 116 | 117 | ChunkPos get_world_spawn_position(uint32_t seed); 118 | -------------------------------------------------------------------------------- /tools.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/12/16. 3 | // 4 | 5 | #include "tools.h" 6 | #include 7 | #include 8 | 9 | bool Vec2i::operator<(const Vec2i &rhs) const { 10 | if (x < rhs.x) 11 | return true; 12 | if (rhs.x < x) 13 | return false; 14 | return z < rhs.z; 15 | } 16 | 17 | bool Vec2i::operator==(const Vec2i &rhs) const { 18 | return x == rhs.x && 19 | z == rhs.z; 20 | } 21 | 22 | bool Box::operator<(const Box &rhs) const { 23 | if (min < rhs.min) 24 | return true; 25 | if (rhs.min < min) 26 | return false; 27 | return max < rhs.max; 28 | } 29 | 30 | bool Box::operator==(const Box &rhs) const { 31 | return min == rhs.min && 32 | max == rhs.max; 33 | } 34 | 35 | void log(const char *file_name, const char *function_name, size_t line, const char *fmt, ...) { 36 | #ifdef DEBUG 37 | va_list args; 38 | va_start(args, fmt); 39 | printf("[%s: %s: %d] ", file_name, function_name, line); 40 | vprintf(fmt, args); 41 | printf("\n"); 42 | #endif 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /tools.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/12/16. 3 | // 4 | 5 | #ifndef MCBE_STRUCTUE_TOOLS_H 6 | #define MCBE_STRUCTUE_TOOLS_H 7 | 8 | #include 9 | #include 10 | 11 | #define DEBUG 12 | #ifdef WIN32 13 | #define FN (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__) 14 | #else 15 | #define FN (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) 16 | #endif 17 | #define LOG(...) log(FN,__FUNCTION__,__LINE__,__VA_ARGS__) 18 | #define ERR(...) fprintf(stderr,__VA_ARGS__) 19 | #define INFO(...) fprintf(stdout,__VA_ARGS__) 20 | 21 | typedef std::chrono::high_resolution_clock timer_clock; 22 | #define TIMER_START auto start = timer_clock::now(); 23 | #define TIMER_END \ 24 | auto elapsed = timer_clock::now() - start; \ 25 | long long timeReslut = \ 26 | std::chrono::duration_cast(elapsed) \ 27 | .count(); 28 | 29 | struct Vec2i { 30 | int x = 0; 31 | int z = 0; 32 | 33 | bool operator<(const Vec2i &rhs) const; 34 | 35 | bool operator==(const Vec2i &rhs) const; 36 | 37 | constexpr Vec2i(int xx, int zz) : x(xx), z(zz) {} 38 | 39 | 40 | Vec2i operator+(const Vec2i &rhs) const { 41 | return {x + rhs.x, z + rhs.z}; 42 | } 43 | 44 | Vec2i operator-(const Vec2i &rhs) const { 45 | return {x - rhs.x, z - rhs.z}; 46 | } 47 | 48 | Vec2i() = default; 49 | }; 50 | 51 | struct Box { 52 | Vec2i min; 53 | Vec2i max; 54 | 55 | bool operator<(const Box &rhs) const; 56 | 57 | bool operator==(const Box &rhs) const; 58 | }; 59 | 60 | typedef Vec2i ChunkPos; 61 | typedef Vec2i Pos; 62 | typedef Vec2i AreaPos; 63 | 64 | template 65 | inline bool between(const T &min, const T &max, const T &x) { 66 | return x >= min && x <= max; 67 | } 68 | 69 | inline Pos scala_down(const Vec2i &origin, int SCALA) { 70 | auto cx = origin.x < 0 ? origin.x + 1 - SCALA : origin.x; 71 | auto cz = origin.z < 0 ? origin.z + 1 - SCALA : origin.z; 72 | return {cx / SCALA, cz / SCALA}; 73 | } 74 | 75 | inline Box scala_up(const Pos &origin, int scala) { 76 | auto x = origin.x * scala; 77 | auto z = origin.z * scala; 78 | return {{x, z}, 79 | {x + scala - 1, z + scala - 1} 80 | }; 81 | } 82 | 83 | //get the fisrt number(>= begin) which === remain (mod module) 84 | //返回区间[begin,+inf)中和remain同余的最小的数(模modulo) 85 | inline int get_cong_with_module(int begin, int modulo, int remain) { 86 | int r = begin - (begin % modulo); 87 | if (begin > 0) 88 | r += modulo; 89 | auto c1 = r + remain; 90 | return between(begin, begin + modulo, c1) ? c1 : c1 - modulo; 91 | } 92 | 93 | 94 | void log(const char *file_name, const char *function_name, size_t line, const char *fmt, ...); 95 | 96 | 97 | #endif //MCBE_STRUCTUE_TOOLS_H 98 | --------------------------------------------------------------------------------