From 6097e42ea610379bc2d7d30e47333fe7be20bfcb Mon Sep 17 00:00:00 2001 From: Cubitect Date: Sun, 9 Aug 2020 18:52:58 +0200 Subject: [PATCH] Changes to API, fixes and performance improvments. 1) Layer functions now return an int and can terminate the generation. 2) This makes it possible to write much more accurate and faster biome finders. 3) The generator structure LayerStack is now stack allocatable and no longer requires a free. 4) Adjustments to make targets. --- find_compactbiomes.c | 9 +- find_quadhuts.c | 10 +- finders.c | 1290 +++++++++++++++++++++++++++++------------- finders.h | 81 +-- generator.c | 144 ++--- generator.h | 101 ++-- layers.c | 458 ++++++++++----- layers.h | 91 +-- makefile | 14 +- 9 files changed, 1436 insertions(+), 762 deletions(-) diff --git a/find_compactbiomes.c b/find_compactbiomes.c index 4a0c1c7..eb258f6 100644 --- a/find_compactbiomes.c +++ b/find_compactbiomes.c @@ -24,12 +24,16 @@ static DWORD WINAPI searchCompactBiomesThread(LPVOID data) int64_t s; int mcversion = MC_1_14; - LayerStack g = setupGenerator(mcversion); + LayerStack g; + setupGenerator(&g, mcversion); int *cache = allocCache(&g.layers[L_VORONOI_ZOOM_1], w, h); for (s = info.seedStart; s != info.seedEnd; s++) { - if (checkForBiomes(&g, cache, s, ax, az, w, h, info.filter, info.minscale)) + if (!hasAllTemps(&g, s, 0, 0)) + continue; + + if (checkForBiomes(&g, L_VORONOI_ZOOM_1, cache, s, ax, az, w, h, info.filter, 1) > 0) { int x, z; if (info.withHut) @@ -70,7 +74,6 @@ static DWORD WINAPI searchCompactBiomesThread(LPVOID data) } } - freeGenerator(g); free(cache); #ifdef USE_PTHREAD diff --git a/find_quadhuts.c b/find_quadhuts.c index b2c8ee1..09624d4 100644 --- a/find_quadhuts.c +++ b/find_quadhuts.c @@ -70,20 +70,15 @@ int main(int argc, char *argv[]) { featureConfig = SWAMP_HUT_CONFIG; seedFileName = "./seeds/quadhutbases_1_13_Q1.txt"; - // setupGeneratorMC113() biome generation is slower and unnecessary. - // We are only interested in the biomes on land, which haven't changed - // since MC 1.7 except for some modified variants. - g = setupGenerator(MC_1_7); - // Use the 1.13 Hills layer to get the correct modified biomes. - g.layers[L_HILLS_64].getMap = mapHills113; } else { featureConfig = FEATURE_CONFIG; seedFileName = "./seeds/quadhutbases_1_7_Q1.txt"; - g = setupGenerator(MC_1_7); } + setupGenerator(&g, mcversion); + //seedFileName = "./seeds/quadbases_Q1b.txt"; if (access(seedFileName, F_OK)) @@ -208,7 +203,6 @@ int main(int argc, char *argv[]) } free(biomeCache); - freeGenerator(g); return 0; } diff --git a/finders.c b/finders.c index 8a139e1..70272f3 100644 --- a/finders.c +++ b/finders.c @@ -942,10 +942,10 @@ int isTreasureChunk(int64_t seed, const int chunkX, const int chunkZ) //============================================================================== -int getBiomeAtPos(const LayerStack g, const Pos pos) +int getBiomeAtPos(const LayerStack *g, const Pos pos) { - int *map = allocCache(&g.layers[L_VORONOI_ZOOM_1], 1, 1); - genArea(&g.layers[L_VORONOI_ZOOM_1], map, pos.x, pos.z, 1, 1); + int *map = allocCache(g->entry_1, 1, 1); + genArea(g->entry_1, map, pos.x, pos.z, 1, 1); int biomeID = map[0]; free(map); return biomeID; @@ -1056,7 +1056,8 @@ int areBiomesViable( } map = cache ? cache : allocCache(l, width, height); - genArea(l, map, x1, z1, width, height); + if (genArea(l, map, x1, z1, width, height)) + return 0; for (i = 0; i < width*height; i++) { @@ -1270,7 +1271,7 @@ static double getGrassProbability(int64_t seed, int biome, int x, int z) static int canCoordinateBeSpawn(const int64_t seed, const LayerStack *g, int *cache, Pos pos) { - int biome = getBiomeAtPos(*g, pos); + int biome = getBiomeAtPos(g, pos); return getGrassProbability(seed, biome, pos.x, pos.z) >= 0.5; } @@ -1366,7 +1367,7 @@ Pos estimateSpawn(const int mcversion, const LayerStack *g, int *cache, int64_t Pos spawn; int found; - Layer *l = &g->layers[L_RIVER_MIX_4]; + const Layer *l = &g->layers[L_RIVER_MIX_4]; setSeed(&worldSeed); spawn = findBiomePosition(mcversion, l, cache, 0, 0, 256, isSpawnBiome, @@ -1396,7 +1397,8 @@ int isViableFeatureBiome(int structureType, int biomeID) case Igloo: return biomeID == snowy_tundra || biomeID == snowy_taiga; case Jungle_Pyramid: - return biomeID == jungle || biomeID == jungle_hills || biomeID == bamboo_jungle || biomeID == bamboo_jungle_hills; + return (biomeID == jungle || biomeID == jungle_hills || + biomeID == bamboo_jungle || biomeID == bamboo_jungle_hills); case Swamp_Hut: return biomeID == swamp; case Ocean_Ruin: @@ -1406,7 +1408,18 @@ int isViableFeatureBiome(int structureType, int biomeID) case Ruined_Portal: return 1; case Treasure: - return biomeID == beach || biomeID == snowy_beach || biomeID == stone_shore || biomeID == mushroom_field_shore; + return (biomeID == beach || biomeID == snowy_beach || + biomeID == stone_shore || biomeID == mushroom_field_shore); + case Monument: + return isOceanic(biomeID); + case Village: + case Outpost: + // differs across MC versions + return (biomeID == plains || biomeID == desert || + biomeID == savanna || biomeID == taiga || + biomeID == snowy_taiga || biomeID == snowy_tundra); + case Mansion: + return biomeID == dark_forest || biomeID == dark_forest_hills; default: fprintf(stderr, "ERR isViableFeatureBiome: not implemented for structure type.\n"); exit(1); @@ -1463,17 +1476,116 @@ static const char *getValidMansionBiomes() } +static int mapViableBiome(const Layer * l, int * out, int x, int z, int w, int h) +{ + int err = mapBiome(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + const StructureConfig *sconf = (const StructureConfig*) l->data; + int styp = sconf->structType; + int i, j; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + int biomeID = out[i + w*j]; + switch (styp) + { + case Desert_Pyramid: + if (biomeID == desert || getBiomeType(biomeID) == Mesa) + return 0; + break; + case Igloo: + if (biomeID == snowy_tundra || biomeID == snowy_taiga) + return 0; + break; + case Jungle_Pyramid: + if (biomeID == jungle) + return 0; + break; + case Swamp_Hut: + if (biomeID == swamp) + return 0; + break; + case Ocean_Ruin: + case Shipwreck: + case Monument: + if (isOceanic(biomeID)) + return 0; + break; + case Mansion: + if (biomeID == dark_forest) + return 0; + break; + default: + return 0; + } + } + } + + return 1; // required biomes not found: set err status to stop generator +} + +static int mapViableShore(const Layer * l, int * out, int x, int z, int w, int h) +{ + int err = mapShore(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + const StructureConfig *sconf = (const StructureConfig*) l->data; + int styp = sconf->structType; + int i, j; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + int biomeID = out[i + w*j]; + switch (styp) + { + case Desert_Pyramid: + case Igloo: + case Jungle_Pyramid: + case Swamp_Hut: + case Ocean_Ruin: + case Shipwreck: + case Village: + case Monument: + case Mansion: + if (isViableFeatureBiome(styp, biomeID)) + return 0; + break; + + default: + return 0; + } + } + } + + return 1; +} + + int isViableStructurePos(const StructureConfig sconf, int mcversion, LayerStack *g, int64_t seed, int blockX, int blockZ) { - int biomeID; int *map = NULL; Layer *l; + int biome; + int viable; int64_t chunkX = blockX >> 4; int64_t chunkZ = blockZ >> 4; - // TODO: where possible perform cheaper biome checks before full validation + Layer lbiome = g->layers[L_BIOME_256]; + Layer lshore = g->layers[L_SHORE_16]; + + g->layers[L_BIOME_256].data = (void*) &sconf; + g->layers[L_BIOME_256].getMap = mapViableBiome; + g->layers[L_SHORE_16].data = (void*) &sconf; + g->layers[L_SHORE_16].getMap = mapViableShore; switch (sconf.structType) { @@ -1483,43 +1595,52 @@ int isViableStructurePos(const StructureConfig sconf, int mcversion, case Swamp_Hut: case Ocean_Ruin: case Shipwreck: - case Ruined_Portal: case Treasure: if (mcversion < MC_1_16) { l = &g->layers[L_VORONOI_ZOOM_1]; - setWorldSeed(l, seed); - map = allocCache(l, 1, 1); - genArea(l, map, blockX, blockZ, 1, 1); } - else // position and layer check changed position in 1.16 - { - l = &g->layers[L_RIVER_MIX_4]; // oceanic checks should be fine here - setWorldSeed(l, seed); - map = allocCache(l, 1, 1); - genArea(l, map, (chunkX << 2) + 2, (chunkZ << 2) + 2, 1, 1); + else + { // In 1.16 the position and layer for the biome dependence changed + // to the centre of a chunk at scale 4. Using L_RIVER_MIX_4 + // (without ocean type) should be fine for ruins and wrecks. + l = &g->layers[L_RIVER_MIX_4]; + blockX = (chunkX << 2) + 2; + blockZ = (chunkZ << 2) + 2; } - biomeID = map[0]; - free(map); - return isViableFeatureBiome(sconf.structType, biomeID); + setWorldSeed(l, seed); + map = allocCache(l, 1, 1); + if (genArea(l, map, blockX, blockZ, 1, 1)) + goto L_NOT_VIABLE; + if (!isViableFeatureBiome(sconf.structType, map[0])) + goto L_NOT_VIABLE; + goto L_VIABLE; case Village: + if (mcversion < MC_1_16) + { // TODO: check this (and if it makes a difference) + blockX >>= 2; + blockZ >>= 2; + } + else + { + blockX = (chunkX << 2) + 2; + blockZ = (chunkZ << 2) + 2; + } l = &g->layers[L_RIVER_MIX_4]; setWorldSeed(l, seed); map = allocCache(l, 1, 1); - if (mcversion < MC_1_16) // TODO: check this (and if it makes a difference) - genArea(l, map, blockX >> 2, blockZ >> 2, 1, 1); + if (genArea(l, map, blockX, blockZ, 1, 1)) + goto L_NOT_VIABLE; + biome = map[0]; + if (biome == plains || biome == desert || biome == savanna || biome == taiga) + goto L_VIABLE; + else if (mcversion >= MC_1_14 && biome == snowy_tundra) + goto L_VIABLE; + else if (mcversion == MC_BE && biome == snowy_taiga) + goto L_VIABLE; else - genArea(l, map, (chunkX << 2) + 2, (chunkZ << 2) + 2, 1, 1); - biomeID = map[0]; - free(map); - if (biomeID == plains || biomeID == desert || biomeID == savanna || biomeID == taiga) - return 1; - if (mcversion >= MC_1_14 && biomeID == snowy_tundra) - return 1; - if (mcversion == MC_BE && biomeID == snowy_taiga) - return 1; - return 0; + goto L_NOT_VIABLE; case Outpost: { @@ -1528,26 +1649,25 @@ int isViableStructurePos(const StructureConfig sconf, int mcversion, setSeed(&rnds); next(&rnds, 32); if (nextInt(&rnds, 5) != 0) - return 0; + goto L_NOT_VIABLE; if (mcversion < MC_1_16) { l = &g->layers[L_VORONOI_ZOOM_1]; - setWorldSeed(l, seed); - map = allocCache(l, 1, 1); - genArea(l, map, blockX, blockZ, 1, 1); } else { - l = &g->layers[L_RIVER_MIX_4]; // oceanic checks should be fine here - setWorldSeed(l, seed); - map = allocCache(l, 1, 1); - genArea(l, map, (chunkX << 2) + 2, (chunkZ << 2) + 2, 1, 1); + l = &g->layers[L_RIVER_MIX_4]; + blockX = (chunkX << 2) + 2; + blockZ = (chunkZ << 2) + 2; } - biomeID = map[0]; - free(map); + setWorldSeed(l, seed); + map = allocCache(l, 1, 1); + if (genArea(l, map, blockX, blockZ, 1, 1)) + goto L_NOT_VIABLE; + biome = map[0]; // TODO: support for MC_BE - if (biomeID != plains && biomeID != desert && biomeID != taiga && biomeID != snowy_tundra && biomeID != savanna) - return 0; + if (biome != plains && biome != desert && biome != taiga && biome != snowy_tundra && biome != savanna) + goto L_NOT_VIABLE; // look for villages within 10 chunks int cx0 = (chunkX-10), cx1 = (chunkX+10); int cz0 = (chunkZ-10), cz1 = (chunkZ+10); @@ -1561,17 +1681,26 @@ int isViableStructurePos(const StructureConfig sconf, int mcversion, if (cx >= cx0 && cx <= cx1 && cz >= cz0 && cz <= cz1) { if (mcversion >= MC_1_16) - return 0; + goto L_NOT_VIABLE; if (isViableStructurePos(VILLAGE_CONFIG, mcversion, g, seed, p.x, p.z)) - return 0; - return 1; + goto L_NOT_VIABLE; + goto L_VIABLE; } } } - return 1; + goto L_VIABLE; } case Monument: + // Monuments require two viability checks with the ocean layer branch => + // worth checking for potential deep ocean beforehand. + l = &g->layers[L_SHORE_16]; + setWorldSeed(l, seed); + map = allocCache(l, 1, 1); + if (genArea(l, map, chunkX, chunkZ, 1, 1)) + goto L_NOT_VIABLE; + if (!isDeepOcean(map[0])) + goto L_NOT_VIABLE; if (mcversion >= MC_1_13) l = &g->layers[L13_OCEAN_MIX_4]; else @@ -1579,18 +1708,37 @@ int isViableStructurePos(const StructureConfig sconf, int mcversion, setWorldSeed(l, seed); if (areBiomesViable(l, NULL, blockX, blockZ, 16, getValidMonumentBiomes1())) if (areBiomesViable(l, NULL, blockX, blockZ, 29, getValidMonumentBiomes2())) - return 1; - return 0; + goto L_VIABLE; + goto L_NOT_VIABLE; case Mansion: l = &g->layers[L_RIVER_MIX_4]; setWorldSeed(l, seed); - return areBiomesViable(l, NULL, blockX, blockZ, 32, getValidMansionBiomes()); + if (areBiomesViable(l, NULL, blockX, blockZ, 32, getValidMansionBiomes())) + goto L_VIABLE; + goto L_NOT_VIABLE; + + case Ruined_Portal: + goto L_VIABLE; default: fprintf(stderr, "ERR isViableStructurePos: validation for structure type not implemented"); - return 0; + goto L_NOT_VIABLE; } + +L_NOT_VIABLE: + viable = 0; + if (0) { +L_VIABLE: + viable = 1; + } + + g->layers[L_BIOME_256] = lbiome; + g->layers[L_SHORE_16] = lshore; + if (map) + free(map); + + return viable; } @@ -1665,428 +1813,763 @@ BiomeFilter setupBiomeFilter(const int *biomeList, int listLen) for (i = 0; i < listLen; i++) { - id = biomeList[i] & 0x7f; + id = biomeList[i]; + if (id & ~0xbf) // i.e. not in ranges [0,64),[128,192) + { + fprintf(stderr, "ERR: biomeID=%d not supported by filter.\n", id); + exit(-1); + } + switch (id) { case mushroom_fields: + // mushroom shores can generate with hills and at rivers + bf.raresToFind |= (1ULL << mushroom_fields); case mushroom_field_shore: - bf.requireMushroom = 1; - bf.tempCat |= (1ULL << Oceanic); - bf.biomesToFind |= (1ULL << id); - case badlands: - case wooded_badlands_plateau: + bf.tempsToFind |= (1ULL << Oceanic); + bf.majorToFind |= (1ULL << mushroom_fields); + bf.riverToFind |= (1ULL << id); + break; + case badlands_plateau: - bf.tempCat |= (1ULL << (Warm+Special)); - bf.biomesToFind |= (1ULL << id); - break; - case savanna: - case savanna_plateau: - bf.tempCat |= (1ULL << Warm); - bf.biomesToFind |= (1ULL << id); - break; - case dark_forest: - case birch_forest: - case birch_forest_hills: - case swamp: - bf.tempCat |= (1ULL << Lush); - bf.biomesToFind |= (1ULL << id); + case wooded_badlands_plateau: + case badlands: + case eroded_badlands: + case modified_badlands_plateau: + case modified_wooded_badlands_plateau: + bf.tempsToFind |= (1ULL << (Warm+Special)); + if (id == badlands_plateau || id == modified_badlands_plateau) + bf.majorToFind |= (1ULL << badlands_plateau); + if (id == wooded_badlands_plateau || id == modified_wooded_badlands_plateau) + bf.majorToFind |= (1ULL << wooded_badlands_plateau); + if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } break; + case jungle: + case jungle_edge: case jungle_hills: - bf.tempCat |= (1ULL << (Lush+Special)); - bf.biomesToFind |= (1ULL << id); + case modified_jungle: + case modified_jungle_edge: + case bamboo_jungle: + case bamboo_jungle_hills: + bf.tempsToFind |= (1ULL << (Lush+Special)); + bf.majorToFind |= (1ULL << jungle); + if (id == bamboo_jungle || id == bamboo_jungle_hills) { + // bamboo%64 are End biomes, so we can reuse the edgesToFind + bf.edgesToFind |= (1ULL << (bamboo_jungle & 0x3f)); + } else if (id == jungle_edge) { + // un-modified jungle_edge can be created at shore layer + bf.riverToFind |= (1ULL << jungle_edge); + } else { + if (id == modified_jungle_edge) + bf.edgesToFind |= (1ULL << jungle_edge); + else + bf.edgesToFind |= (1ULL << jungle); + if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } + } break; - /*case jungleEdge: - bf.tempCat |= (1ULL << Lush) | (1ULL << Lush+4); - bf.biomesToFind |= (1ULL << id); - break;*/ + case giant_tree_taiga: case giant_tree_taiga_hills: - bf.tempCat |= (1ULL << (Cold+Special)); - bf.biomesToFind |= (1ULL << id); + case giant_spruce_taiga: + case giant_spruce_taiga_hills: + bf.tempsToFind |= (1ULL << (Cold+Special)); + bf.majorToFind |= (1ULL << giant_tree_taiga); + bf.edgesToFind |= (1ULL << giant_tree_taiga); + if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } break; - case snowy_tundra: - case snowy_mountains: + + case savanna: + case savanna_plateau: + case shattered_savanna: + case shattered_savanna_plateau: + case desert_hills: + case desert_lakes: + bf.tempsToFind |= (1ULL << Warm); + if (id == desert_hills || id == desert_lakes) { + bf.majorToFind |= (1ULL << desert); + bf.edgesToFind |= (1ULL << desert); + } else { + bf.majorToFind |= (1ULL << savanna); + bf.edgesToFind |= (1ULL << savanna); + } + if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } + break; + + case dark_forest: + case dark_forest_hills: + case birch_forest: + case birch_forest_hills: + case tall_birch_forest: + case tall_birch_hills: + case swamp: + case swamp_hills: + bf.tempsToFind |= (1ULL << Lush); + if (id == dark_forest || id == dark_forest_hills) { + bf.majorToFind |= (1ULL << dark_forest); + bf.edgesToFind |= (1ULL << dark_forest); + } + else if (id == birch_forest || id == birch_forest_hills || + id == tall_birch_forest || id == tall_birch_hills) { + bf.majorToFind |= (1ULL << birch_forest); + bf.edgesToFind |= (1ULL << birch_forest); + } + else if (id == swamp || id == swamp_hills) { + bf.majorToFind |= (1ULL << swamp); + bf.edgesToFind |= (1ULL << swamp); + } + if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } + break; + case snowy_taiga: case snowy_taiga_hills: - bf.tempCat |= (1ULL << Freezing); - bf.biomesToFind |= (1ULL << id); - break; - default: - bf.biomesToFind |= (1ULL << id); - - if (isOceanic(id)) - { - if (id != ocean && id != deep_ocean) - bf.doOceanTypeCheck = 1; - - if (isShallowOcean(id)) - { - bf.oceansToFind |= (1ULL << id); - } - else - { - if (id == deep_warm_ocean) - bf.oceansToFind |= (1ULL << warm_ocean); - else if (id == deep_lukewarm_ocean) - bf.oceansToFind |= (1ULL << lukewarm_ocean); - else if (id == deep_ocean) - bf.oceansToFind |= (1ULL << ocean); - else if (id == deep_cold_ocean) - bf.oceansToFind |= (1ULL << cold_ocean); - else if (id == deep_frozen_ocean) - bf.oceansToFind |= (1ULL << frozen_ocean); - } - bf.tempCat |= (1ULL << Oceanic); - } + case snowy_taiga_mountains: + case snowy_tundra: + case snowy_mountains: + case ice_spikes: + case frozen_river: + bf.tempsToFind |= (1ULL << Freezing); + if (id == snowy_taiga || id == snowy_taiga_hills || + id == snowy_taiga_mountains) + bf.edgesToFind |= (1ULL << snowy_taiga); else - { - bf.biomesToFind |= (1ULL << id); + bf.edgesToFind |= (1ULL << snowy_tundra); + if (id == frozen_river) { + bf.raresToFind |= (1ULL << snowy_tundra); + bf.riverToFind |= (1ULL << id); + } else if (id < 128) { + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + } else { + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + } + break; + + case sunflower_plains: + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + break; + + case snowy_beach: + bf.tempsToFind |= (1ULL << Freezing); + case beach: + case stone_shore: + bf.riverToFind |= (1ULL << id); + break; + + case mountains: + bf.majorToFind |= (1ULL << mountains); + case wooded_mountains: + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + break; + case gravelly_mountains: + bf.majorToFind |= (1ULL << mountains); + case modified_gravelly_mountains: + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + break; + + case taiga: + case taiga_hills: + bf.edgesToFind |= (1ULL << taiga); + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + break; + case taiga_mountains: + bf.edgesToFind |= (1ULL << taiga); + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + break; + + case plains: + case forest: + case wooded_hills: + bf.raresToFind |= (1ULL << id); + bf.riverToFind |= (1ULL << id); + break; + case flower_forest: + bf.raresToFindM |= (1ULL << (id-128)); + bf.riverToFindM |= (1ULL << (id-128)); + break; + + case desert: // can generate at shore layer + bf.riverToFind |= (1ULL << id); + break; + + default: + if (isOceanic(id)) { + bf.tempsToFind |= (1ULL << Oceanic); + bf.oceanToFind |= (1ULL << id); + if (isShallowOcean(id)) { + bf.otempToFind |= (1ULL << id); + } else { + bf.raresToFind |= (1ULL << deep_ocean); + bf.riverToFind |= (1ULL << deep_ocean); + if (id == deep_warm_ocean) + bf.otempToFind |= (1ULL << warm_ocean); + else if (id == deep_lukewarm_ocean) + bf.otempToFind |= (1ULL << lukewarm_ocean); + else if (id == deep_ocean) + bf.otempToFind |= (1ULL << ocean); + else if (id == deep_cold_ocean) + bf.otempToFind |= (1ULL << cold_ocean); + else if (id == deep_frozen_ocean) + bf.otempToFind |= (1ULL << frozen_ocean); + } + } else { + if (id < 64) + bf.riverToFind |= (1ULL << id); + else + bf.riverToFindM |= (1ULL << (id-128)); } break; } } - for (i = 0; i < Special; i++) - { - if (bf.tempCat & (1ULL << i)) bf.tempNormal++; - } - for (i = Special; i < Freezing+Special; i++) - { - if (bf.tempCat & (1ULL << i)) bf.tempSpecial++; - } + bf.shoreToFind = bf.riverToFind; + bf.shoreToFind &= ~((1ULL << river) | (1ULL << frozen_river)); + bf.shoreToFindM = bf.riverToFindM; - bf.doTempCheck = (bf.tempSpecial + bf.tempNormal) >= 6; - bf.doShroomAndTempCheck = bf.requireMushroom && (bf.tempSpecial >= 1 || bf.tempNormal >= 4); - bf.doMajorBiomeCheck = 1; - bf.checkBiomePotential = 1; - bf.doScale4Check = 1; + bf.specialCnt = 0; + bf.specialCnt += !!(bf.tempsToFind & (1ULL << (Warm+Special))); + bf.specialCnt += !!(bf.tempsToFind & (1ULL << (Lush+Special))); + bf.specialCnt += !!(bf.tempsToFind & (1ULL << (Cold+Special))); return bf; } - -/* Tries to determine if the biomes configured in the filter will generate in - * this seed within the specified area. The smallest layer scale checked is - * given by 'minscale'. Lowering this value terminate the search earlier and - * yield more false positives. - */ -int64_t checkForBiomes( - LayerStack * g, - int * cache, - const int64_t seed, - const int blockX, - const int blockZ, - const unsigned int width, - const unsigned int height, - const BiomeFilter filter, - const int minscale) +static int mapFilterSpecial(const Layer * l, int * out, int x, int z, int w, int h) { - Layer *lspecial = &g->layers[L_SPECIAL_1024]; - Layer *lmushroom = &g->layers[L_ADD_MUSHROOM_256]; - Layer *lbiomes = &g->layers[L_BIOME_256]; - Layer *loceantemp = NULL; + const BiomeFilter *bf = (const BiomeFilter*) l->data; + int i, j; + uint64_t temps; - int *map = cache ? cache : allocCache(&g->layers[L_VORONOI_ZOOM_1], width, height); - - uint64_t potential, required, modified; - int64_t ss, cs; - int id, types[0x100]; - int i, x, z; - int areaX1024, areaZ1024, areaWidth1024, areaHeight1024; - int areaX256, areaZ256, areaWidth256, areaHeight256; - int areaX4, areaZ4, areaWidth4, areaHeight4; - - // 1:1024 scale - areaX1024 = blockX >> 10; - areaZ1024 = blockZ >> 10; - areaWidth1024 = ((width-1) >> 10) + 2; - areaHeight1024 = ((height-1) >> 10) + 2; - - // 1:256 scale - areaX256 = blockX >> 8; - areaZ256 = blockZ >> 8; - areaWidth256 = ((width-1) >> 8) + 2; - areaHeight256 = ((height-1) >> 8) + 2; - - - /*** BIOME CHECKS THAT DON'T NEED OTHER LAYERS ***/ - - // Check that there is the necessary minimum of both special and normal - // temperature categories present. - if (filter.tempNormal || filter.tempSpecial) + /// pre-gen checks + int specialcnt = bf->specialCnt; + if (specialcnt > 0) { - ss = getStartSeed(seed, lspecial->layerSeed); + int64_t ss = l->startSeed; + int64_t cs; - types[0] = types[1] = 0; - for (z = 0; z < areaHeight1024; z++) + for (j = 0; j < h; j++) { - for (x = 0; x < areaWidth1024; x++) + for (i = 0; i < w; i++) { - cs = getChunkSeed(ss, x + areaX1024, z + areaZ1024); - types[mcFirstInt(cs, 13) == 0]++; + cs = getChunkSeed(ss, x+i, z+j); + if (mcFirstIsZero(cs, 13)) + specialcnt--; } } + if (specialcnt > 0) + return 1; + } - if (types[0] < filter.tempNormal || types[1] < filter.tempSpecial) + int err = mapSpecial(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + temps = 0; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) { - goto return_zero; + int id = out[i + w*j]; + int isspecial = id & 0xf00; + id &= ~0xf00; + if (isspecial && id != Freezing) + temps |= (1ULL << (id+Special)); + else + temps |= (1ULL << id); } } - // Check there is a mushroom island, provided there is an ocean. - if (filter.requireMushroom) - { - ss = getStartSeed(seed, lmushroom->layerSeed); + if ((temps & bf->tempsToFind) ^ bf->tempsToFind) + return 1; + return 0; +} - for (z = 0; z < areaHeight256; z++) +static int mapFilterMushroom(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + int i, j; + int err; + + if (w*h < 100 && bf->majorToFind & (1ULL << mushroom_fields)) + { + int64_t ss = l->startSeed; + int64_t cs; + + for (j = 0; j < h; j++) { - for (x = 0; x < areaWidth256; x++) + for (i = 0; i < w; i++) { - cs = getChunkSeed(ss, x + areaX256, z + areaZ256); - if (mcFirstInt(cs, 100) == 0) + cs = getChunkSeed(ss, i+x, j+z); + if (mcFirstIsZero(cs, 100)) + goto L_GENERATE; + } + } + return 1; + } + +L_GENERATE: + err = mapAddMushroomIsland(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + if (bf->majorToFind & (1ULL << mushroom_fields)) + { + for (i = 0; i < w*h; i++) + if (out[i] == mushroom_fields) + return 0; + return 1; + } + return 0; +} + +static int mapFilterBiome(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + int i, j; + uint64_t b; + + int err = mapBiome(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + b = 0; + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + int id = out[i + w*j]; + b |= (1ULL << id); + } + } + + if ((b & bf->majorToFind) ^ bf->majorToFind) + return 1; + return 0; +} + +static int mapFilterOceanTemp(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + int i, j; + uint64_t b; + + int err = mapOceanTemp(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + b = 0; + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + int id = out[i + w*j]; + b |= (1ULL << id); + } + } + + if ((b & bf->otempToFind) ^ bf->otempToFind) + return 1; + return 0; +} + +static int mapFilterBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + uint64_t b; + int i; + int err; + + err = mapBiomeEdge(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + b = 0; + for (i = 0; i < w*h; i++) + b |= (1ULL << (out[i] & 0x3f)); + + if ((b & bf->edgesToFind) ^ bf->edgesToFind) + return 1; + return 0; +} + +static int mapFilterRareBiome(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + uint64_t b, bm; + int i; + int err; + + err = mapRareBiome(l, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; + + b = 0; bm = 0; + for (i = 0; i < w*h; i++) + { + int id = out[i]; + if (id < 128) b |= (1ULL << id); + else bm |= (1ULL << (id-128)); + } + + if ((b & bf->raresToFind) ^ bf->raresToFind) + return 1; + if ((bm & bf->raresToFindM) ^ bf->raresToFindM) + return 1; + return 0; +} + +static int mapFilterShore(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + uint64_t b, bm; + int i; + + int err = mapShore(l, out, x, z, w, h); + if (EXPECT(err, 0)) return err; + + b = 0; bm = 0; + for (i = 0; i < w*h; i++) + { + int id = out[i]; + if (id < 128) b |= (1ULL << id); + else bm |= (1ULL << (id-128)); + } + + if ((b & bf->shoreToFind) ^ bf->shoreToFind) + return 1; + if ((bm & bf->shoreToFindM) ^ bf->shoreToFindM) + return 1; + return 0; +} + +static int mapFilterRiverMix(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + uint64_t b, bm; + int i; + + int err = mapRiverMix(l, out, x, z, w, h); + if (EXPECT(err, 0)) return err; + + b = 0; bm = 0; + for (i = 0; i < w*h; i++) + { + int id = out[i]; + if (id < 128) b |= (1ULL << id); + else bm |= (1ULL << (id-128)); + } + + if ((b & bf->riverToFind) ^ bf->riverToFind) + return 1; + if ((bm & bf->riverToFindM) ^ bf->riverToFindM) + return 1; + return 0; +} + +static int mapFilterOceanMix(const Layer * l, int * out, int x, int z, int w, int h) +{ + const BiomeFilter *bf = (const BiomeFilter*) l->data; + uint64_t b; + int i; + int err; + + if (bf->riverToFind) + { + err = mapRiverMix(l, out, x, z, w, h); + if (err) return err; + } + + err = mapOceanMix(l, out, x, z, w, h); + if (EXPECT(err, 0)) return err; + + b = 0; + for (i = 0; i < w*h; i++) + { + int id = out[i]; + if (id < 128) b |= (1ULL << id); + } + + if ((b & bf->oceanToFind) ^ bf->oceanToFind) + return 1; + return 0; +} + + +int checkForBiomes( + LayerStack * g, + int layerID, + int * cache, + int64_t seed, + int x, + int z, + unsigned int w, + unsigned int h, + BiomeFilter filter, + int protoCheck + ) +{ + Layer *l; + + if (protoCheck) + { + l = &g->layers[layerID]; + + int i, j; + int bx = x * l->scale; + int bz = z * l->scale; + int bw = w * l->scale; + int bh = h * l->scale; + int x0, z0, x1, z1; + int64_t ss, cs; + uint64_t potential, required; + + int specialcnt = filter.specialCnt; + if (specialcnt > 0) + { + l = &g->layers[L_SPECIAL_1024]; + x0 = (bx) / l->scale; if (x < 0) x0--; + z0 = (bz) / l->scale; if (z < 0) z0--; + x1 = (bx + bw) / l->scale; if (x+w >= 0) x1++; + z1 = (bz + bh) / l->scale; if (z+h >= 0) z1++; + ss = getStartSeed(seed, l->layerSeed); + + for (j = z0; j <= z1; j++) + { + for (i = x0; i <= x1; i++) { - goto after_protomushroom; + cs = getChunkSeed(ss, i, j); + if (mcFirstIsZero(cs, 13)) + specialcnt--; } } + if (specialcnt > 0) + return 0; } - goto return_zero; - } - after_protomushroom: + l = &g->layers[L_BIOME_256]; + x0 = bx / l->scale; if (x < 0) x0--; + z0 = bz / l->scale; if (z < 0) z0--; + x1 = (bx + bw) / l->scale; if (x+w >= 0) x1++; + z1 = (bz + bh) / l->scale; if (z+h >= 0) z1++; - if (filter.checkBiomePotential) - { - ss = getStartSeed(seed, lbiomes->layerSeed); + if (filter.majorToFind & (1ULL << mushroom_fields)) + { + ss = getStartSeed(seed, g->layers[L_ADD_MUSHROOM_256].layerSeed); + + for (j = z0; j <= z1; j++) + { + for (i = x0; i <= x1; i++) + { + cs = getChunkSeed(ss, i, j); + if (mcFirstIsZero(cs, 100)) + goto L_HAS_PROTO_MUSHROOM; + } + } + return 0; + } +L_HAS_PROTO_MUSHROOM: potential = 0; - required = filter.biomesToFind & ( + required = filter.majorToFind & ( (1ULL << badlands_plateau) | (1ULL << wooded_badlands_plateau) | - (1ULL << savanna) | (1ULL << dark_forest) | - (1ULL << birch_forest) | (1ULL << swamp)); + (1ULL << desert) | (1ULL << savanna) | (1ULL << plains) | + (1ULL << forest) | (1ULL << dark_forest) | (1ULL << mountains) | + (1ULL << birch_forest) | (1ULL << swamp)); - for (z = 0; z < areaHeight256; z++) + ss = getStartSeed(seed, l->layerSeed); + + for (j = z0; j <= z1; j++) { - for (x = 0; x < areaWidth256; x++) + for (i = x0; i <= x1; i++) { - cs = getChunkSeed(ss, x + areaX256, z + areaZ256); - cs >>= 24; + cs = getChunkSeed(ss, i, j); + int cs6 = mcFirstInt(cs, 6); + int cs3 = mcFirstInt(cs, 3); + int cs4 = mcFirstInt(cs, 4); - int cs6 = cs % 6; - int cs3 = cs6 & 3; + if (cs3) potential |= (1ULL << badlands_plateau); + else potential |= (1ULL << wooded_badlands_plateau); - if (cs3 == 0) potential |= (1ULL << badlands_plateau); - else if (cs3 == 1 || cs3 == 2) potential |= (1ULL << wooded_badlands_plateau); - - if (cs6 == 1) potential |= (1ULL << dark_forest); - else if (cs6 == 3) potential |= (1ULL << savanna); - else if (cs6 == 4) potential |= (1ULL << savanna) | (1ULL << birch_forest); - else if (cs6 == 5) potential |= (1ULL << swamp); - - if (!((potential & required) ^ required)) + switch (cs6) { - goto after_protobiome; + case 0: potential |= (1ULL << desert) | (1ULL << forest); break; + case 1: potential |= (1ULL << desert) | (1ULL << dark_forest); break; + case 2: potential |= (1ULL << desert) | (1ULL << mountains); break; + case 3: potential |= (1ULL << savanna) | (1ULL << plains); break; + case 4: potential |= (1ULL << savanna) | (1ULL << birch_forest); break; + case 5: potential |= (1ULL << plains) | (1ULL << swamp); break; } + + if (cs4 == 3) potential |= (1ULL << snowy_taiga); + else potential |= (1ULL << snowy_tundra); } } - goto return_zero; - } - after_protobiome: - - - /*** BIOME CHECKS ***/ - - if (filter.doTempCheck) - { - setWorldSeed(lspecial, seed); - genArea(lspecial, map, areaX1024, areaZ1024, areaWidth1024, areaHeight1024); - - potential = 0; - - for (i = 0; i < areaWidth1024 * areaHeight1024; i++) - { - id = map[i]; - if (id >= Special) id = (id & 0xf) + Special; - potential |= (1ULL << id); - } - - if ((potential & filter.tempCat) ^ filter.tempCat) - { - goto return_zero; - } - } - - if (minscale > 256) goto return_one; - - if (filter.doShroomAndTempCheck) - { - setWorldSeed(lmushroom, seed); - genArea(lmushroom, map, areaX256, areaZ256, areaWidth256, areaHeight256); - - potential = 0; - - for (i = 0; i < areaWidth256 * areaHeight256; i++) - { - id = map[i]; - if (id >= BIOME_NUM) id = (id & 0xf) + Special; - potential |= (1ULL << id); - } - - required = filter.tempCat | (1ULL << mushroom_fields); - if ((potential & required) ^ required) - { - goto return_zero; - } + return 0; } - if (filter.doOceanTypeCheck) + l = &g->layers[layerID]; + int *map = cache ? cache : allocCache(l, w, h); + + g->layers[L_SPECIAL_1024].data = (void*) &filter; + g->layers[L_SPECIAL_1024].getMap = mapFilterSpecial; + g->layers[L_ADD_MUSHROOM_256].data = (void*) &filter; + g->layers[L_ADD_MUSHROOM_256].getMap = mapFilterMushroom; + g->layers[L_BIOME_256].data = (void*) &filter; + g->layers[L_BIOME_256].getMap = mapFilterBiome; + g->layers[L13_OCEAN_TEMP_256].data = (void*) &filter; + g->layers[L13_OCEAN_TEMP_256].getMap = mapFilterOceanTemp; + g->layers[L_BIOME_EDGE_64].data = (void*) &filter; + g->layers[L_BIOME_EDGE_64].getMap = mapFilterBiomeEdge; + g->layers[L_RARE_BIOME_64].data = (void*) &filter; + g->layers[L_RARE_BIOME_64].getMap = mapFilterRareBiome; + g->layers[L_SHORE_16].data = (void*) &filter; + g->layers[L_SHORE_16].getMap = mapFilterShore; + g->layers[L_RIVER_MIX_4].data = (void*) &filter; + g->layers[L_RIVER_MIX_4].getMap = mapFilterRiverMix; + g->layers[L13_OCEAN_MIX_4].data = (void*) &filter; + g->layers[L13_OCEAN_MIX_4].getMap = mapFilterOceanMix; + + setWorldSeed(l, seed); + int ret = !l->getMap(l, map, x, z, w, h); + if (ret) { - loceantemp = &g->layers[L13_OCEAN_TEMP_256]; - setWorldSeed(loceantemp, seed); - genArea(loceantemp, map, areaX256, areaZ256, areaWidth256, areaHeight256); - - potential = 0; // ocean potential - - for (i = 0; i < areaWidth256 * areaHeight256; i++) + uint64_t required, b = 0, bm = 0; + unsigned int i; + for (i = 0; i < w*h; i++) { - id = map[i]; - if (id == warm_ocean) potential |= (1ULL << warm_ocean) | (1ULL << lukewarm_ocean); - if (id == lukewarm_ocean) potential |= (1ULL << lukewarm_ocean); - if (id == ocean) potential |= (1ULL << ocean); - if (id == cold_ocean) potential |= (1ULL << cold_ocean); - if (id == frozen_ocean) potential |= (1ULL << frozen_ocean) | (1ULL << cold_ocean); - } - - if ((potential & filter.oceansToFind) ^ filter.oceansToFind) - { - goto return_zero; + int id = map[i]; + if (id < 128) b |= (1ULL << id); + else bm |= (1ULL << (id-128)); } + required = filter.riverToFind; + required &= ~((1ULL << ocean) | (1ULL << deep_ocean)); + required |= filter.oceanToFind; + if ((b & required) ^ required) + ret = -1; + required = filter.riverToFindM; + if ((bm & required) ^ required) + ret = -1; } - if (filter.doMajorBiomeCheck) - { - setWorldSeed(lbiomes, seed); - genArea(lbiomes, map, areaX256, areaZ256, areaWidth256, areaHeight256); + g->layers[L_SPECIAL_1024].data = NULL; + g->layers[L_SPECIAL_1024].getMap = mapSpecial; + g->layers[L_ADD_MUSHROOM_256].data = NULL; + g->layers[L_ADD_MUSHROOM_256].getMap = mapAddMushroomIsland; + g->layers[L_BIOME_256].data = NULL; + g->layers[L_BIOME_256].getMap = mapBiome; + g->layers[L13_OCEAN_TEMP_256].data = NULL; + g->layers[L13_OCEAN_TEMP_256].getMap = mapOceanTemp; + g->layers[L_BIOME_EDGE_64].data = NULL; + g->layers[L_BIOME_EDGE_64].getMap = mapBiomeEdge; + g->layers[L_RARE_BIOME_64].data = NULL; + g->layers[L_RARE_BIOME_64].getMap = mapRareBiome; + g->layers[L_SHORE_16].data = NULL; + g->layers[L_SHORE_16].getMap = mapShore; + g->layers[L_RIVER_MIX_4].data = NULL; + g->layers[L_RIVER_MIX_4].getMap = mapRiverMix; + g->layers[L13_OCEAN_MIX_4].data = NULL; + g->layers[L13_OCEAN_MIX_4].getMap = mapOceanMix; - // get biomes out of the way that we cannot check for at this layer - potential = (1ULL << beach) | (1ULL << stone_shore) | - (1ULL << snowy_beach) | (1ULL << river) | (1ULL << frozen_river); - - for (i = 0; i < areaWidth256 * areaHeight256; i++) - { - id = map[i]; - switch (id) - { - case wooded_badlands_plateau: - case badlands_plateau: - potential |= (1ULL << id) | (1ULL << badlands) | (1ULL << desert); break; - case giant_tree_taiga: - potential |= (1ULL << id) | (1ULL << taiga) | (1ULL << taiga_hills) | (1ULL << giant_tree_taiga_hills); break; - case desert: - potential |= (1ULL << id) | (1ULL << wooded_mountains) | (1ULL << desert_hills); break; - case swamp: - potential |= (1ULL << id) | (1ULL << jungleEdge) | (1ULL << plains); break; - case forest: - potential |= (1ULL << id) | (1ULL << wooded_hills); break; - case birch_forest: - potential |= (1ULL << id) | (1ULL << birch_forest_hills); break; - case dark_forest: - potential |= (1ULL << id) | (1ULL << plains); break; - case taiga: - potential |= (1ULL << id) | (1ULL << taiga_hills); break; - case snowy_taiga: - potential |= (1ULL << id) | (1ULL << snowy_taiga_hills); break; - case plains: - potential |= (1ULL << id) | (1ULL << wooded_hills) | (1ULL << forest); break; - case snowy_tundra: - potential |= (1ULL << id) | (1ULL << snowy_mountains); break; - case jungle: - potential |= (1ULL << id) | (1ULL << jungle_hills); break; - case ocean: - potential |= (1ULL << id) | (1ULL << deep_ocean); - // TODO: buffer possible ocean types at this location - potential |= (1ULL << frozen_ocean) | (1ULL << cold_ocean) | (1ULL << lukewarm_ocean) | (1ULL << warm_ocean); break; - case mountains: - potential |= (1ULL << id) | (1ULL << wooded_mountains); break; - case savanna: - potential |= (1ULL << id) | (1ULL << savanna_plateau); break; - case deep_ocean: - potential |= (1ULL << id) | (1ULL << plains) | (1ULL << forest); - // TODO: buffer possible ocean types at this location - potential |= (1ULL << deep_frozen_ocean) | (1ULL << deep_cold_ocean) | (1ULL << deep_lukewarm_ocean); break; - case mushroom_fields: - potential |= (1ULL << id) | (1ULL << mushroom_field_shore); - default: - potential |= (1ULL << id); - } - } - - if ((potential & filter.biomesToFind) ^ filter.biomesToFind) - { - goto return_zero; - } - } - - // TODO: Do a check at the HILLS layer, scale 1:64 - - if (minscale > 4) goto return_one; - - if (filter.doScale4Check) - { - // 1:4 scale - areaX4 = blockX >> 2; - areaZ4 = blockZ >> 2; - areaWidth4 = ((width-1) >> 2) + 2; - areaHeight4 = ((height-1) >> 2) + 2; - - applySeed(g, seed); - if (filter.doOceanTypeCheck) - genArea(&g->layers[L13_OCEAN_MIX_4], map, areaX4, areaZ4, areaWidth4, areaHeight4); - else - genArea(&g->layers[L_RIVER_MIX_4], map, areaX4, areaZ4, areaWidth4, areaHeight4); - - potential = modified = 0; - - for (i = 0; i < areaWidth4 * areaHeight4; i++) - { - id = map[i]; - if (id >= 128) modified |= (1ULL << (id & 0x7f)); - else potential |= (1ULL << id); - } - - required = filter.biomesToFind; - if ((potential & required) ^ required) - { - goto return_zero; - } - if ((modified & filter.modifiedToFind) ^ filter.modifiedToFind) - { - goto return_zero; - } - } - - - int ret; - - // clean up and return - return_one: - ret = 1; - - if (0) - { - return_zero: - ret = 0; - } - - if (cache == NULL) free(map); + if (cache == NULL) + free(map); return ret; } +int hasAllTemps(LayerStack *g, int64_t seed, int x1024, int z1024) +{ + int64_t ls; + ls = getLayerSeed(3); // L_SPECIAL_1024 layer seed + + int64_t ss = getStartSeed(seed, ls); + int spbits = 0, spcnt = 0; + + if (mcFirstIsZero(getChunkSeed(ss, x1024-1, z1024-1), 13)) + { spbits |= (1<<0); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024 , z1024-1), 13)) + { spbits |= (1<<1); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024+1, z1024-1), 13)) + { spbits |= (1<<2); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024-1, z1024 ), 13)) + { spbits |= (1<<3); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024 , z1024 ), 13)) + { spbits |= (1<<4); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024+1, z1024 ), 13)) + { spbits |= (1<<5); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024-1, z1024+1), 13)) + { spbits |= (1<<6); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024 , z1024+1), 13)) + { spbits |= (1<<7); spcnt++; } + if (mcFirstIsZero(getChunkSeed(ss, x1024+1, z1024+1), 13)) + { spbits |= (1<<8); spcnt++; } + + if (spcnt < 3) + return 0; + + // approx. ~2.7% of seeds make it to here + + int buf[20*20]; + int i; + + setWorldSeed(&g->layers[L_HEAT_ICE_1024], seed); + genArea(&g->layers[L_HEAT_ICE_1024], buf, x1024-1, z1024-1, 3, 3); + + uint64_t bm = 0; + for (i = 0; i < 9; i++) + { + int id = buf[i]; + if (id != 0 && id != Freezing && (spbits & (1<= 128 && biomeID < 192) + uint64_t raresToFind, raresToFindM; + uint64_t shoreToFind, shoreToFindM; + uint64_t riverToFind, riverToFindM; + uint64_t oceanToFind; // all required ocean types - // check that there is a minimum of both special and normal temperatures - int tempNormal, tempSpecial; - // check for the temperatures specified by tempCnt (1:1024) - int doTempCheck; - // check for mushroom potential - int requireMushroom; - // combine a more detailed mushroom and temperature check (1:256) - int doShroomAndTempCheck; - // early check for 1.13 ocean types (1:256) - int doOceanTypeCheck; - // - int doMajorBiomeCheck; - // pre-generation biome checks in layer L_BIOME_256 - int checkBiomePotential; - // - int doScale4Check; + int specialCnt; // number of special temperature categories required }; #ifdef __cplusplus @@ -277,7 +266,7 @@ int isTreasureChunk(int64_t seed, const int chunkX, const int chunkZ); /* Returns the biome for the specified block position. * (Alternatives should be considered first in performance critical code.) */ -int getBiomeAtPos(const LayerStack g, const Pos pos); +int getBiomeAtPos(const LayerStack *g, const Pos pos); /* Finds a suitable pseudo-random location in the specified area. * This function is used to determine the positions of spawn and strongholds. @@ -468,21 +457,35 @@ int64_t getHouseList(const int64_t worldSeed, const int chunkX, const int chunkZ */ BiomeFilter setupBiomeFilter(const int *biomeList, int listLen); -/* Tries to determine if the biomes configured in the filter will generate in - * this seed within the specified area. The smallest layer scale checked is - * given by 'minscale'. Lowering this value terminate the search earlier and - * yield more false positives. +/* Starts to generate the specified area and checks if all biomes in the filter + * are present. If so, the area will be fully generated inside the cache + * (if != NULL) up to the entry 'layerID', and the return value will be > 0. + * Otherwise, the contents of 'cache' is undefined and a value <= 0 is returned. + * More aggressive filtering can be enabled with 'protoCheck' which may yield + * some false negatives in exchange for speed. + * + * @g : generator (will be modified!) + * @layerID : layer enum of generation entry point + * @cache : working buffer, and output (if != NULL) + * @seed : world seed + * @x,z,w,h : requested area + * @filter : biomes to be checked for + * @protoCheck : enables more aggressive filtering when non-zero */ -int64_t checkForBiomes( - LayerStack * g, - int * cache, - const int64_t seed, - const int blockX, - const int blockZ, - const unsigned int width, - const unsigned int height, - const BiomeFilter filter, - const int minscale); +int checkForBiomes( + LayerStack * g, + int layerID, + int * cache, + int64_t seed, + int x, + int z, + unsigned int w, + unsigned int h, + BiomeFilter filter, + int protoCheck + ); + +int hasAllTemps(LayerStack *g, int64_t seed, int x1024, int z1024); #ifdef __cplusplus } diff --git a/generator.c b/generator.c index bf00cd0..c4a98d8 100644 --- a/generator.c +++ b/generator.c @@ -7,8 +7,7 @@ -void setupLayer(Layer *l, Layer *p, int s, - void (*getMap)(const Layer *, int *, int, int, int, int)) +void setupLayer(Layer *l, Layer *p, int s, mapfunc_t getMap) { l->layerSeed = getLayerSeed(s); l->startSalt = 0; @@ -16,27 +15,65 @@ void setupLayer(Layer *l, Layer *p, int s, l->p = p; l->p2 = NULL; l->scale = 0; + l->edge = 0; l->getMap = getMap; l->oceanRnd = NULL; + l->data = NULL; } -void setupMultiLayer(Layer *l, Layer *p1, Layer *p2, int s, - void (*getMap)(const Layer *, int *, int, int, int, int)) +void setupMultiLayer(Layer *l, Layer *p1, Layer *p2, int s, mapfunc_t getMap) { setupLayer(l, p1, s, getMap); l->p2 = p2; } - static void setupScale(Layer *l, int scale) { l->scale = scale; int m = 1; - if (l->getMap == mapZoom) { + int e = 0; + + mapfunc_t map = l->getMap; + + if (map == mapZoom) + { m = 2; - } else if (l->getMap == mapVoronoiZoom) { - m = 4; + e = 2; // from ((w>>1)+1)<<1 } + else if (map == mapVoronoiZoom) + { + m = 4; + e = 8; // from ((w>>2)+2)<<2 + } + else if (map == mapOceanMix) + { + e = 17; + } + else if ( + map == mapAddIsland || + map == mapRemoveTooMuchOcean || + map == mapAddSnow || + map == mapCoolWarm || + map == mapHeatIce || + map == mapAddMushroomIsland || + map == mapDeepOcean || + map == mapBiomeEdge || + map == mapHills || + map == mapHills113 || + map == mapRiver || + map == mapSmooth || + map == mapShore + ) + { + e = 2; + } + else + { + e = 0; + } + + l->edge = e; + if (l->p) { setupScale(l->p, scale * m); } @@ -45,21 +82,19 @@ static void setupScale(Layer *l, int scale) } } -static LayerStack setupGeneratorImpl(const int mcversion, const int largeBiomes) +static void setupGeneratorImpl(LayerStack *g, int mcversion, int largeBiomes) { if (biomes[plains].id == 0) { fprintf(stderr, "Warning: The biomes have to be initialised first using initBiomes() before any generator can be used.\n"); } - LayerStack g; - g.layerCnt = L_NUM; - g.layers = (Layer *) calloc(g.layerCnt, sizeof(Layer)); - Layer *l = g.layers; + memset(g, 0, sizeof(LayerStack)); + Layer *l = g->layers; // LAYER PARENT SALT LAYER_FUNCTION setupLayer(&l[L_ISLAND_4096], NULL, 1, mapIsland); - setupLayer(&l[L_ZOOM_2048], &l[L_ISLAND_4096], 2000, mapZoom); + setupLayer(&l[L_ZOOM_2048], &l[L_ISLAND_4096], 2000, mapZoomIsland); setupLayer(&l[L_ADD_ISLAND_2048], &l[L_ZOOM_2048], 1, mapAddIsland); setupLayer(&l[L_ZOOM_1024], &l[L_ADD_ISLAND_2048], 2001, mapZoom); setupLayer(&l[L_ADD_ISLAND_1024A], &l[L_ZOOM_1024], 2, mapAddIsland); @@ -130,50 +165,39 @@ static LayerStack setupGeneratorImpl(const int mcversion, const int largeBiomes) if (mcversion <= MC_1_12) { - setupLayer(&l[L_VORONOI_ZOOM_1], &l[L_RIVER_MIX_4], 10, mapVoronoiZoom); + setupLayer(&l[L_VORONOI_ZOOM_1], &l[L_RIVER_MIX_4], 10, mapVoronoiZoom); + g->entry_4 = &l[L_RIVER_MIX_4]; } else { // ocean variants - setupLayer(&l[L13_OCEAN_TEMP_256], NULL, 2, mapOceanTemp); - l[L13_OCEAN_TEMP_256].oceanRnd = (OceanRnd *) malloc(sizeof(OceanRnd)); - setupLayer(&l[L13_ZOOM_128], &l[L13_OCEAN_TEMP_256], 2001, mapZoom); - setupLayer(&l[L13_ZOOM_64], &l[L13_ZOOM_128], 2002, mapZoom); - setupLayer(&l[L13_ZOOM_32], &l[L13_ZOOM_64], 2003, mapZoom); - setupLayer(&l[L13_ZOOM_16], &l[L13_ZOOM_32], 2004, mapZoom); - setupLayer(&l[L13_ZOOM_8], &l[L13_ZOOM_16], 2005, mapZoom); - setupLayer(&l[L13_ZOOM_4], &l[L13_ZOOM_8], 2006, mapZoom); + setupLayer(&l[L13_OCEAN_TEMP_256], NULL, 2, mapOceanTemp); + l[L13_OCEAN_TEMP_256].oceanRnd = &g->oceanRnd; + setupLayer(&l[L13_ZOOM_128], &l[L13_OCEAN_TEMP_256], 2001, mapZoom); + setupLayer(&l[L13_ZOOM_64], &l[L13_ZOOM_128], 2002, mapZoom); + setupLayer(&l[L13_ZOOM_32], &l[L13_ZOOM_64], 2003, mapZoom); + setupLayer(&l[L13_ZOOM_16], &l[L13_ZOOM_32], 2004, mapZoom); + setupLayer(&l[L13_ZOOM_8], &l[L13_ZOOM_16], 2005, mapZoom); + setupLayer(&l[L13_ZOOM_4], &l[L13_ZOOM_8], 2006, mapZoom); setupMultiLayer(&l[L13_OCEAN_MIX_4], &l[L_RIVER_MIX_4], &l[L13_ZOOM_4], 100, mapOceanMix); - setupLayer(&l[L_VORONOI_ZOOM_1], &l[L13_OCEAN_MIX_4], 10, mapVoronoiZoom); + setupLayer(&l[L_VORONOI_ZOOM_1], &l[L13_OCEAN_MIX_4], 10, mapVoronoiZoom); + g->entry_4 = &l[L13_OCEAN_MIX_4]; } setupScale(&l[L_VORONOI_ZOOM_1], 1); - - return g; + g->entry_1 = &l[L_VORONOI_ZOOM_1]; } -LayerStack setupGenerator(const int mcversion) +void setupGenerator(LayerStack *g, int mcversion) { - return setupGeneratorImpl(mcversion, 0); + setupGeneratorImpl(g, mcversion, 0); } -LayerStack setupLargeBiomesGenerator(const int mcversion) +void setupLargeBiomesGenerator(LayerStack *g, int mcversion) { - return setupGeneratorImpl(mcversion, 1); -} - -void freeGenerator(LayerStack g) -{ - int i; - for(i = 0; i < g.layerCnt; i++) - { - if (g.layers[i].oceanRnd != NULL) - free(g.layers[i].oceanRnd); - } - - free(g.layers); + setupGeneratorImpl(g, mcversion, 1); } @@ -187,36 +211,18 @@ static void getMaxArea(const Layer *layer, int areaX, int areaZ, int *maxX, int if (layer->getMap == mapZoom) { - areaX = (areaX >> 1) + 2; - areaZ = (areaZ >> 1) + 2; + areaX >>= 1; + areaZ >>= 1; } else if (layer->getMap == mapVoronoiZoom) { - areaX = (areaX >> 2) + 3; - areaZ = (areaZ >> 2) + 3; - } - else if (layer->getMap == mapOceanMix) - { - areaX += 17; - areaZ += 17; - } - else - { - if (layer->getMap != mapNull && - layer->getMap != mapSkip && - layer->getMap != mapIsland && - layer->getMap != mapSpecial && - layer->getMap != mapBiome && - layer->getMap != mapRareBiome && - layer->getMap != mapRiverInit && - layer->getMap != mapRiverMix && - layer->getMap != mapOceanTemp) - { - areaX += 2; - areaZ += 2; - } + areaX >>= 2; + areaZ >>= 2; } + areaX += layer->edge; + areaZ += layer->edge; + if (areaX > *maxX) *maxX = areaX; if (areaZ > *maxZ) *maxZ = areaZ; @@ -249,10 +255,10 @@ void applySeed(LayerStack *g, int64_t seed) setWorldSeed(&g->layers[L_VORONOI_ZOOM_1], seed); } -void genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight) +int genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight) { memset(out, 0, areaWidth*areaHeight*sizeof(*out)); - layer->getMap(layer, out, areaX, areaZ, areaWidth, areaHeight); + return layer->getMap(layer, out, areaX, areaZ, areaWidth, areaHeight); } diff --git a/generator.h b/generator.h index 2d1ade4..8383cdd 100644 --- a/generator.h +++ b/generator.h @@ -6,7 +6,7 @@ /* Minecraft versions */ enum MCversion { - MC_1_7, MC_1_8, MC_1_9, MC_1_10, MC_1_11, MC_1_12, MC_1_13, MC_1_14, + MC_1_7, MC_1_8, MC_1_9, MC_1_10, MC_1_11, MC_1_12, MC_1_13, MC_1_14, MC_1_15, MC_1_16, MC_BE = 128 }; @@ -80,6 +80,58 @@ enum }; +STRUCT(LayerStack) +{ + Layer layers[L_NUM]; + Layer *entry_1; // entry layer, scale (1:1) [L_VORONOI_ZOOM_1] + Layer *entry_4; // entry layer, scale (1:4) [L_RIVER_MIX_4|L13_OCEAN_MIX_4] + OceanRnd oceanRnd; +}; + +typedef int (*mapfunc_t)(const Layer *, int *, int, int, int, int); + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialise an instance of a generator. */ +void setupGenerator(LayerStack *g, int mcversion); + +/* Initialise an instance of a generator with largeBiomes configuration. */ +void setupLargeBiomesGenerator(LayerStack *g, int mcversion); + + +/* Calculates the minimum size of the buffers required to generate an area of + * dimensions 'sizeX' by 'sizeZ' at the specified layer. + */ +int calcRequiredBuf(const Layer *layer, int areaX, int areaZ); + +/* Allocates an amount of memory required to generate an area of dimensions + * 'sizeX' by 'sizeZ' for the magnification of the given layer. + */ +int *allocCache(const Layer *layer, int sizeX, int sizeZ); + + +/* Set up custom layers. */ +void setupLayer(Layer *l, Layer *p, int s, mapfunc_t getMap); +void setupMultiLayer(Layer *l, Layer *p1, Layer *p2, int s, mapfunc_t getMap); + +/* Sets the world seed for the generator */ +void applySeed(LayerStack *g, int64_t seed); + +/* Generates the specified area using the current generator settings and stores + * the biomeIDs in 'out'. + * The biomeIDs will be indexed in the form: out[x + z*areaWidth] + * It is recommended that 'out' is allocated using allocCache() for the correct + * buffer size. + */ +int genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight); + + + + /******************************** BIOME TABLES ********************************* * The biome tables below are lists of the biomes that can be present at some * notable layers. Of cause, layers that are applied later in the hierarchy will @@ -187,53 +239,6 @@ static const int BIOMES_L_RIVER_MIX_4[] = }; -STRUCT(LayerStack) -{ - Layer *layers; - int layerCnt; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialise an instance of a generator. */ -LayerStack setupGenerator(const int mcversion); - -/* Initialise an instance of a generator with largeBiomes configuration. */ -LayerStack setupLargeBiomesGenerator(const int mcversion); - -/* Cleans up and frees the generator layers */ -void freeGenerator(LayerStack g); - - -/* Calculates the minimum size of the buffers required to generate an area of - * dimensions 'sizeX' by 'sizeZ' at the specified layer. - */ -int calcRequiredBuf(const Layer *layer, int areaX, int areaZ); - -/* Allocates an amount of memory required to generate an area of dimensions - * 'sizeX' by 'sizeZ' for the magnification of the current top layer. - */ -int *allocCache(const Layer *layer, int sizeX, int sizeZ); - - -/* Set up custom layers. */ -void setupLayer(Layer *l, Layer *p, int s, void (*getMap)(const Layer *, int *, int, int, int, int)); -void setupMultiLayer(Layer *l, Layer *p1, Layer *p2, int s, void (*getMap)(const Layer *, int *, int, int, int, int)); - -/* Sets the world seed for the generator */ -void applySeed(LayerStack *g, int64_t seed); - -/* Generates the specified area using the current generator settings and stores - * the biomeIDs in 'out'. - * The biomeIDs will be indexed in the form: out[x + z*areaWidth] - * It is recommended that 'out' is allocated using allocCache() for the correct - * buffer size. - */ -void genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight); - #ifdef __cplusplus } diff --git a/layers.c b/layers.c index 54297a4..e5100d1 100644 --- a/layers.c +++ b/layers.c @@ -3,13 +3,6 @@ #include #include -#if __GNUC__ -#define PREFETCH(PTR) __builtin_prefetch(PTR) -#define EXPECT(COND,VAL) __builtin_expect(COND,VAL) -#else -#define PREFETCH(PTR) -#define EXPECT(COND,VAL) (COND) -#endif static void oceanRndInit(OceanRnd *rnd, int64_t seed); @@ -24,7 +17,7 @@ void initAddBiome(int id, int tempCat, int biometype, float temp, float height) biomes[id].tempCat = tempCat; } -void createMutation(int id) +static void createMutation(int id) { biomes[id].mutated = id + 128; biomes[id+128] = biomes[id]; @@ -157,22 +150,7 @@ void setWorldSeed(Layer *layer, int64_t worldSeed) } -void mapNull(const Layer * l, int * out, int x, int z, int w, int h) -{ -} - -void mapSkip(const Layer * l, int * out, int x, int z, int w, int h) -{ - if (l->p == NULL) - { - printf("mapSkip() requires a non-null parent layer.\n"); - exit(1); - } - l->p->getMap(l->p, out, x, z, w, h); -} - - -void mapIsland(const Layer * l, int * out, int x, int z, int w, int h) +int mapIsland(const Layer * l, int * out, int x, int z, int w, int h) { int64_t ss = l->startSeed; int64_t cs; @@ -191,12 +169,11 @@ void mapIsland(const Layer * l, int * out, int x, int z, int w, int h) { out[-x + -z * w] = 1; } + + return 0; } - -/// This is the most common layer, and generally the second most performance -/// critical after mapAddIsland. -void mapZoom(const Layer * l, int * out, int x, int z, int w, int h) +int mapZoomIsland(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x >> 1; int pZ = z >> 1; @@ -204,18 +181,18 @@ void mapZoom(const Layer * l, int * out, int x, int z, int w, int h) int pH = ((z + h) >> 1) - pZ + 1; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; int newW = (pW) << 1; int newH = (pH) << 1; - int idx, v00, v01; + int idx, v00, v01, v10, v11; int *buf = (int*) malloc((newW+1)*(newH+1)*sizeof(*buf)); const int st = (int)l->startSalt; const int ss = (int)l->startSeed; - int isHighestZoom = l->p->getMap == mapIsland; - for (j = 0; j < pH; j++) { idx = (j << 1) * newW; @@ -223,10 +200,20 @@ void mapZoom(const Layer * l, int * out, int x, int z, int w, int h) v00 = out[(j+0)*pW]; v01 = out[(j+1)*pW]; - for (i = 0; i < pW; i++) + for (i = 0; i < pW; i++, v00 = v10, v01 = v11) { - int v10 = out[i+1 + (j+0)*pW]; - int v11 = out[i+1 + (j+1)*pW]; + v10 = out[i+1 + (j+0)*pW]; + v11 = out[i+1 + (j+1)*pW]; + + if (v00 == v01 && v00 == v10 && v00 == v11) + { + buf[idx] = v00; + buf[idx + 1] = v00; + buf[idx + newW] = v00; + buf[idx + newW + 1] = v00; + idx += 2; + continue; + } int chunkX = (i + pX) << 1; int chunkZ = (j + pZ) << 1; @@ -248,42 +235,11 @@ void mapZoom(const Layer * l, int * out, int x, int z, int w, int h) cs += st; buf[idx] = (cs >> 24) & 1 ? v10 : v00; - - if (isHighestZoom) - { - //selectRandom4 - cs *= cs * 1284865837 + 4150755663; - cs += st; - int r = (cs >> 24) & 3; - buf[idx + newW] = r==0 ? v00 : r==1 ? v10 : r==2 ? v01 : v11; - } - else - { - //selectModeOrRandom - int v; - if (v10 == v01 && v01 == v11) v = v10; - else if (v00 == v10 && v00 == v01) v = v00; - else if (v00 == v10 && v00 == v11) v = v00; - else if (v00 == v01 && v00 == v11) v = v00; - else if (v00 == v10 && v01 != v11) v = v00; - else if (v00 == v01 && v10 != v11) v = v00; - else if (v00 == v11 && v10 != v01) v = v00; - else if (v10 == v01 && v00 != v11) v = v10; - else if (v10 == v11 && v00 != v01) v = v10; - else if (v01 == v11 && v00 != v10) v = v01; - else - { - cs *= cs * 1284865837 + 4150755663; - cs += st; - int r = (cs >> 24) & 3; - v = r==0 ? v00 : r==1 ? v10 : r==2 ? v01 : v11; - } - buf[idx + newW] = v; - } - + cs *= cs * 1284865837 + 4150755663; + cs += st; + int r = (cs >> 24) & 3; + buf[idx + newW] = r==0 ? v00 : r==1 ? v10 : r==2 ? v01 : v11; idx++; - v00 = v10; - v01 = v11; } } @@ -293,10 +249,110 @@ void mapZoom(const Layer * l, int * out, int x, int z, int w, int h) } free(buf); + + return 0; +} + +/// This is the most common layer, and generally the second most performance +/// critical after mapAddIsland. +int mapZoom(const Layer * l, int * out, int x, int z, int w, int h) +{ + int pX = x >> 1; + int pZ = z >> 1; + int pW = ((x + w) >> 1) - pX + 1; + int pH = ((z + h) >> 1) - pZ + 1; + int i, j; + + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; + + int newW = (pW) << 1; + int newH = (pH) << 1; + int idx, v00, v01, v10, v11; + int *buf = (int*) malloc((newW+1)*(newH+1)*sizeof(*buf)); + + const int st = (int)l->startSalt; + const int ss = (int)l->startSeed; + + for (j = 0; j < pH; j++) + { + idx = (j << 1) * newW; + + v00 = out[(j+0)*pW]; + v01 = out[(j+1)*pW]; + + for (i = 0; i < pW; i++, v00 = v10, v01 = v11) + { + v10 = out[i+1 + (j+0)*pW]; + v11 = out[i+1 + (j+1)*pW]; + + if (v00 == v01 && v00 == v10 && v00 == v11) + { + buf[idx] = v00; + buf[idx + 1] = v00; + buf[idx + newW] = v00; + buf[idx + newW + 1] = v00; + idx += 2; + continue; + } + + int chunkX = (i + pX) << 1; + int chunkZ = (j + pZ) << 1; + + int cs = ss; + cs += chunkX; + cs *= cs * 1284865837 + 4150755663; + cs += chunkZ; + cs *= cs * 1284865837 + 4150755663; + cs += chunkX; + cs *= cs * 1284865837 + 4150755663; + cs += chunkZ; + + buf[idx] = v00; + buf[idx + newW] = (cs >> 24) & 1 ? v01 : v00; + idx++; + + cs *= cs * 1284865837 + 4150755663; + cs += st; + buf[idx] = (cs >> 24) & 1 ? v10 : v00; + + int v; + if (v10 == v01 && v01 == v11) v = v10; + else if (v00 == v10 && v00 == v01) v = v00; + else if (v00 == v10 && v00 == v11) v = v00; + else if (v00 == v01 && v00 == v11) v = v00; + else if (v00 == v10 && v01 != v11) v = v00; + else if (v00 == v01 && v10 != v11) v = v00; + else if (v00 == v11 && v10 != v01) v = v00; + else if (v10 == v01 && v00 != v11) v = v10; + else if (v10 == v11 && v00 != v01) v = v10; + else if (v01 == v11 && v00 != v10) v = v01; + else + { + cs *= cs * 1284865837 + 4150755663; + cs += st; + int r = (cs >> 24) & 3; + v = r==0 ? v00 : r==1 ? v10 : r==2 ? v01 : v11; + } + buf[idx + newW] = v; + + idx++; + } + } + + for (j = 0; j < h; j++) + { + memcpy(&out[j*w], &buf[(j + (z & 1))*newW + (x & 1)], w*sizeof(int)); + } + + free(buf); + + return 0; } /// This is the most performance crittical layer, especially for getBiomeAtPos. -void mapAddIsland(const Layer * l, int * out, int x, int z, int w, int h) +int mapAddIsland(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -304,7 +360,9 @@ void mapAddIsland(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; int64_t st = l->startSalt; int64_t ss = l->startSeed; @@ -402,10 +460,12 @@ void mapAddIsland(const Layer * l, int * out, int x, int z, int w, int h) v02 = vt2; vt2 = v22; } } + + return 0; } -void mapRemoveTooMuchOcean(const Layer * l, int * out, int x, int z, int w, int h) +int mapRemoveTooMuchOcean(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -413,7 +473,9 @@ void mapRemoveTooMuchOcean(const Layer * l, int * out, int x, int z, int w, int int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -440,10 +502,12 @@ void mapRemoveTooMuchOcean(const Layer * l, int * out, int x, int z, int w, int } } } + + return 0; } -void mapAddSnow(const Layer * l, int * out, int x, int z, int w, int h) +int mapAddSnow(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -451,8 +515,10 @@ void mapAddSnow(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); - + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; + int64_t ss = l->startSeed; int64_t cs; @@ -480,10 +546,12 @@ void mapAddSnow(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapCoolWarm(const Layer * l, int * out, int x, int z, int w, int h) +int mapCoolWarm(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -491,7 +559,9 @@ void mapCoolWarm(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -515,10 +585,12 @@ void mapCoolWarm(const Layer * l, int * out, int x, int z, int w, int h) out[i + j*w] = v11; } } + + return 0; } -void mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h) +int mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -526,7 +598,9 @@ void mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -550,12 +624,16 @@ void mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h) out[i + j*w] = v11; } } + + return 0; } -void mapSpecial(const Layer * l, int * out, int x, int z, int w, int h) +int mapSpecial(const Layer * l, int * out, int x, int z, int w, int h) { - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t st = l->startSalt; int64_t ss = l->startSeed; @@ -580,10 +658,12 @@ void mapSpecial(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapAddMushroomIsland(const Layer * l, int * out, int x, int z, int w, int h) +int mapAddMushroomIsland(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -591,7 +671,9 @@ void mapAddMushroomIsland(const Layer * l, int * out, int x, int z, int w, int h int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -615,10 +697,12 @@ void mapAddMushroomIsland(const Layer * l, int * out, int x, int z, int w, int h out[i + j*w] = v11; } } + + return 0; } -void mapDeepOcean(const Layer * l, int * out, int x, int z, int w, int h) +int mapDeepOcean(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -626,7 +710,9 @@ void mapDeepOcean(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -671,6 +757,8 @@ void mapDeepOcean(const Layer * l, int * out, int x, int z, int w, int h) out[i + j*w] = v11; } } + + return 0; } @@ -679,9 +767,11 @@ const int lushBiomes[] = {forest, dark_forest, mountains, plains, birch_forest, const int coldBiomes[] = {forest, mountains, taiga, plains}; const int snowBiomes[] = {snowy_tundra, snowy_tundra, snowy_tundra, snowy_taiga}; -void mapBiome(const Layer * l, int * out, int x, int z, int w, int h) +int mapBiome(const Layer * l, int * out, int x, int z, int w, int h) { - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -693,8 +783,8 @@ void mapBiome(const Layer * l, int * out, int x, int z, int w, int h) { int idx = i + j*w; int id = out[idx]; - int hasHighBit = (id & 0xf00) >> 8; - id &= -0xf01; + int hasHighBit = (id & 0xf00); + id &= ~0xf00; if (getBiomeType(id) == Ocean || id == mushroom_fields) { @@ -704,7 +794,8 @@ void mapBiome(const Layer * l, int * out, int x, int z, int w, int h) cs = getChunkSeed(ss, i + x, j + z); - switch(id){ + switch (id) + { case Warm: if (hasHighBit) out[idx] = mcFirstIsZero(cs, 3) ? badlands_plateau : wooded_badlands_plateau; else out[idx] = warmBiomes[mcFirstInt(cs, 6)]; @@ -725,14 +816,18 @@ void mapBiome(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } const int lushBiomesBE[] = {forest, dark_forest, mountains, plains, plains, plains, birch_forest, swamp}; -void mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h) +int mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h) { - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -744,8 +839,8 @@ void mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h) { int idx = i + j*w; int id = out[idx]; - int hasHighBit = (id & 0xf00) >> 8; - id &= -0xf01; + int hasHighBit = (id & 0xf00); + id &= ~0xf00; if (getBiomeType(id) == Ocean || id == mushroom_fields) { @@ -755,7 +850,8 @@ void mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h) cs = getChunkSeed(ss, i + x, j + z); - switch(id){ + switch (id) + { case Warm: if (hasHighBit) out[idx] = mcFirstIsZero(cs, 3) ? badlands_plateau : wooded_badlands_plateau; else out[idx] = warmBiomes[mcFirstInt(cs, 6)]; @@ -776,12 +872,16 @@ void mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapRiverInit(const Layer * l, int * out, int x, int z, int w, int h) +int mapRiverInit(const Layer * l, int * out, int x, int z, int w, int h) { - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -802,12 +902,16 @@ void mapRiverInit(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapAddBamboo(const Layer * l, int * out, int x, int z, int w, int h) +int mapAddBamboo(const Layer * l, int * out, int x, int z, int w, int h) { - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -827,6 +931,8 @@ void mapAddBamboo(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } @@ -844,7 +950,7 @@ static inline int replaceEdge(int *out, int idx, int v10, int v21, int v01, int return 1; } -void mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) +int mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -852,7 +958,9 @@ void mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -894,7 +1002,7 @@ void mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) v21 != bamboo_jungle && v01 != bamboo_jungle) out[i + j*w] = v11; else - out[i + j*w] = jungleEdge; + out[i + j*w] = jungle_edge; } else { @@ -908,10 +1016,12 @@ void mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapHills(const Layer * l, int * out, int x, int z, int w, int h) +int mapHills(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -926,12 +1036,19 @@ void mapHills(const Layer * l, int * out, int x, int z, int w, int h) exit(1); } - buf = (int *) malloc(pW*pH*sizeof(int)); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + buf = (int *) malloc(pW*pH*sizeof(int)); memcpy(buf, out, pW*pH*sizeof(int)); - l->p2->getMap(l->p2, out, pX, pZ, pW, pH); + err = l->p2->getMap(l->p2, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + { + free(buf); + return err; + } int64_t st = l->startSalt; int64_t ss = l->startSeed; @@ -1035,10 +1152,11 @@ void mapHills(const Layer * l, int * out, int x, int z, int w, int h) } free(buf); + return 0; } -void mapHills113(const Layer * l, int * out, int x, int z, int w, int h) +int mapHills113(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -1053,12 +1171,19 @@ void mapHills113(const Layer * l, int * out, int x, int z, int w, int h) exit(1); } - buf = (int *) malloc(pW*pH*sizeof(int)); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + buf = (int *) malloc(pW*pH*sizeof(int)); memcpy(buf, out, pW*pH*sizeof(int)); - l->p2->getMap(l->p2, out, pX, pZ, pW, pH); + err = l->p2->getMap(l->p2, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + { + free(buf); + return err; + } int64_t st = l->startSalt; int64_t ss = l->startSeed; @@ -1174,6 +1299,7 @@ void mapHills113(const Layer * l, int * out, int x, int z, int w, int h) } free(buf); + return 0; } @@ -1183,7 +1309,7 @@ static inline int reduceID(int id) return id >= 2 ? 2 + (id & 1) : id; } -void mapRiver(const Layer * l, int * out, int x, int z, int w, int h) +int mapRiver(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -1191,7 +1317,9 @@ void mapRiver(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -1217,10 +1345,12 @@ void mapRiver(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapSmooth(const Layer * l, int * out, int x, int z, int w, int h) +int mapSmooth(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -1228,7 +1358,9 @@ void mapSmooth(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -1267,14 +1399,18 @@ void mapSmooth(const Layer * l, int * out, int x, int z, int w, int h) out[i + j * w] = v11; } } + + return 0; } -void mapRareBiome(const Layer * l, int * out, int x, int z, int w, int h) +int mapRareBiome(const Layer * l, int * out, int x, int z, int w, int h) { int i, j; - l->p->getMap(l->p, out, x, z, w, h); + int err = l->p->getMap(l->p, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; int64_t ss = l->startSeed; int64_t cs; @@ -1296,6 +1432,8 @@ void mapRareBiome(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } @@ -1316,7 +1454,7 @@ inline static int isBiomeJFTO(int id) return biomeExists(id) && (getBiomeType(id) == Jungle || id == forest || id == taiga || isOceanic(id)); } -void mapShore(const Layer * l, int * out, int x, int z, int w, int h) +int mapShore(const Layer * l, int * out, int x, int z, int w, int h) { int pX = x - 1; int pZ = z - 1; @@ -1324,7 +1462,9 @@ void mapShore(const Layer * l, int * out, int x, int z, int w, int h) int pH = h + 2; int i, j; - l->p->getMap(l->p, out, pX, pZ, pW, pH); + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; for (j = 0; j < h; j++) { @@ -1360,7 +1500,7 @@ void mapShore(const Layer * l, int * out, int x, int z, int w, int h) } else { - out[i + j*w] = jungleEdge; + out[i + j*w] = jungle_edge; } } else if (v11 != mountains && v11 != wooded_mountains && v11 != mountain_edge) @@ -1404,10 +1544,12 @@ void mapShore(const Layer * l, int * out, int x, int z, int w, int h) } } } + + return 0; } -void mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h) +int mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h) { int idx; int len; @@ -1419,13 +1561,21 @@ void mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h) exit(1); } + + int err = l->p->getMap(l->p, out, x, z, w, h); // biome chain + if (EXPECT(err, 0)) + return err; + len = w*h; buf = (int *) malloc(len*sizeof(int)); - - l->p->getMap(l->p, out, x, z, w, h); // biome chain memcpy(buf, out, len*sizeof(int)); - l->p2->getMap(l->p2, out, x, z, w, h); // rivers + err = l->p2->getMap(l->p2, out, x, z, w, h); // rivers + if (EXPECT(err, 0)) + { + free(buf); + return err; + } for (idx = 0; idx < len; idx++) { @@ -1452,6 +1602,7 @@ void mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h) } free(buf); + return 0; } @@ -1545,7 +1696,7 @@ static double getOceanTemp(const OceanRnd *rnd, double d1, double d2, double d3) return lerp(t3, l1, l5); } -void mapOceanTemp(const Layer * l, int * out, int x, int z, int w, int h) +int mapOceanTemp(const Layer * l, int * out, int x, int z, int w, int h) { int i, j; OceanRnd *rnd = l->oceanRnd; @@ -1568,10 +1719,12 @@ void mapOceanTemp(const Layer * l, int * out, int x, int z, int w, int h) out[i + j*w] = ocean; } } + + return 0; } -void mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h) +int mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h) { int *land, *otyp; int i, j; @@ -1583,7 +1736,9 @@ void mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h) exit(1); } - l->p2->getMap(l->p2, out, x, z, w, h); + int err = l->p2->getMap(l->p2, out, x, z, w, h); + if (EXPECT(err, 0)) + return err; otyp = (int *) malloc(w*h*sizeof(int)); memcpy(otyp, out, w*h*sizeof(int)); @@ -1612,7 +1767,12 @@ void mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h) lw = lx1 - lx0; lh = lz1 - lz0; - l->p->getMap(l->p, out, x+lx0, z+lz0, lw, lh); + err = l->p->getMap(l->p, out, x+lx0, z+lz0, lw, lh); + if (EXPECT(err, 0)) + { + free(otyp); + return err; + } land = (int *) malloc(lw*lh*sizeof(int)); memcpy(land, out, lw*lh*sizeof(int)); @@ -1680,10 +1840,12 @@ void mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h) free(land); free(otyp); + + return 0; } -void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) +int mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) { x -= 2; z -= 2; @@ -1691,13 +1853,16 @@ void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) int pZ = z >> 2; int pW = ((x + w) >> 2) - pX + 2; int pH = ((z + h) >> 2) - pZ + 2; + + int err = l->p->getMap(l->p, out, pX, pZ, pW, pH); + if (EXPECT(err, 0)) + return err; + int newW = pW << 2; int newH = pH << 2; int i, j; int *buf = (int *) malloc((newW+1)*(newH+1)*sizeof(*buf)); - l->p->getMap(l->p, out, pX, pZ, pW, pH); - int64_t st = l->startSalt; int64_t ss = l->startSeed; int64_t cs; @@ -1706,17 +1871,29 @@ void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) { int v00 = out[(j+0)*pW]; int v01 = out[(j+1)*pW]; + int v10, v11; - for (i = 0; i < pW-1; i++) + for (i = 0; i < pW-1; i++, v00 = v10, v01 = v11) { int ii, jj; int *pbuf = buf + (j << 2) * newW + (i << 2); // try to prefetch the relevant rows to help prevent cache misses - PREFETCH( pbuf + newW*0 ); - PREFETCH( pbuf + newW*1 ); - PREFETCH( pbuf + newW*2 ); - PREFETCH( pbuf + newW*3 ); + PREFETCH( pbuf + newW*0, 1, 1 ); + PREFETCH( pbuf + newW*1, 1, 1 ); + PREFETCH( pbuf + newW*2, 1, 1 ); + PREFETCH( pbuf + newW*3, 1, 1 ); + + v10 = out[i+1 + (j+0)*pW]; + v11 = out[i+1 + (j+1)*pW]; + + if (v00 == v01 && v00 == v10 && v00 == v11) + { + for (jj = 0; jj < 4; jj++) + for (ii = 0; ii < 4; ii++) + pbuf[ii + jj*newW] = v00; + continue; + } cs = getChunkSeed(ss, (i+pX) << 2, (j+pZ) << 2); int64_t da1 = (mcFirstInt(cs, 1024) - 512) * 36; @@ -1738,9 +1915,6 @@ void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) cs = mcStepSeed(cs, st); int64_t dd2 = (mcFirstInt(cs, 1024) - 512) * 36 + 40*1024; - int v10 = out[i+1 + (j+0)*pW]; - int v11 = out[i+1 + (j+1)*pW]; - for (jj = 0; jj < 4; jj++) { int mj = 10240*jj; @@ -1771,9 +1945,6 @@ void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) p[ii] = v; } } - - v00 = v10; - v01 = v11; } } @@ -1783,6 +1954,7 @@ void mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h) } free(buf); + return 0; } diff --git a/layers.h b/layers.h index f0c6581..749dbd6 100644 --- a/layers.h +++ b/layers.h @@ -13,9 +13,16 @@ #define NULL ((void*)0) #endif - #define STRUCT(S) typedef struct S S; struct S +#if __GNUC__ +#define PREFETCH(PTR,RW,LOC) __builtin_prefetch(PTR,RW,LOC) +#define EXPECT(COND,VAL) __builtin_expect(COND,VAL) +#else +#define PREFETCH(PTR) +#define EXPECT(COND,VAL) (COND) +#endif + enum BiomeID { @@ -61,8 +68,8 @@ enum BiomeID wooded_mountains, extremeHillsPlus = wooded_mountains, savanna, savanna_plateau, savannaPlateau = savanna_plateau, - badlands, mesa = badlands, - wooded_badlands_plateau, mesaPlateau_F = wooded_badlands_plateau, + badlands, mesa = badlands, + wooded_badlands_plateau, mesaPlateau_F = wooded_badlands_plateau, badlands_plateau, mesaPlateau = badlands_plateau, // 40 -- 1.13 small_end_islands, @@ -78,9 +85,9 @@ enum BiomeID // 50 deep_frozen_ocean, frozenDeepOcean = deep_frozen_ocean, BIOME_NUM, - + the_void = 127, - + // mutated variants sunflower_plains = plains+128, desert_lakes = desert+128, @@ -149,10 +156,12 @@ STRUCT(Layer) int64_t startSeed; // (world seed dependent) starting point for chunk seeds OceanRnd *oceanRnd; // world seed dependent data for ocean temperatures + void *data; // generic data for custom layers int scale; // map scale of this layer (map entry = scale x scale blocks) + int edge; // maximum border required from parent layer - void (*getMap)(const Layer *, int *, int, int, int, int); + int (*getMap)(const Layer *, int *, int, int, int, int); Layer *p, *p2; // parent layers }; @@ -313,12 +322,19 @@ static inline int64_t getLayerSeed(int64_t salt) return ls; } +static inline int64_t getStartSalt(int64_t ws, int64_t ls) +{ + int64_t st = ws; + st = mcStepSeed(st, ls); + st = mcStepSeed(st, ls); + st = mcStepSeed(st, ls); + return st; +} + static inline int64_t getStartSeed(int64_t ws, int64_t ls) { int64_t ss = ws; - ss = mcStepSeed(ss, ls); - ss = mcStepSeed(ss, ls); - ss = mcStepSeed(ss, ls); + ss = getStartSalt(ss, ls); ss = mcStepSeed(ss, 0); return ss; } @@ -329,41 +345,36 @@ static inline int64_t getStartSeed(int64_t ws, int64_t ls) // Layers //============================================================================== -// A null layer does nothing, and can be used to apply a layer to existing data. -void mapNull (const Layer *, int *, int, int, int, int); -// A skip layer simply calls its first parent without modification. -// This can be used as an easy way to skip a layer in a generator. -void mapSkip (const Layer *, int *, int, int, int, int); - -void mapIsland (const Layer *, int *, int, int, int, int); -void mapZoom (const Layer *, int *, int, int, int, int); -void mapAddIsland (const Layer *, int *, int, int, int, int); -void mapRemoveTooMuchOcean (const Layer *, int *, int, int, int, int); -void mapAddSnow (const Layer *, int *, int, int, int, int); -void mapCoolWarm (const Layer *, int *, int, int, int, int); -void mapHeatIce (const Layer *, int *, int, int, int, int); -void mapSpecial (const Layer *, int *, int, int, int, int); -void mapAddMushroomIsland (const Layer *, int *, int, int, int, int); -void mapDeepOcean (const Layer *, int *, int, int, int, int); -void mapBiome (const Layer *, int *, int, int, int, int); -void mapBiomeBE (const Layer *, int *, int, int, int, int); -void mapAddBamboo (const Layer *, int *, int, int, int, int); -void mapRiverInit (const Layer *, int *, int, int, int, int); -void mapBiomeEdge (const Layer *, int *, int, int, int, int); -void mapHills (const Layer *, int *, int, int, int, int); -void mapRiver (const Layer *, int *, int, int, int, int); -void mapSmooth (const Layer *, int *, int, int, int, int); -void mapRareBiome (const Layer *, int *, int, int, int, int); -void mapShore (const Layer *, int *, int, int, int, int); -void mapRiverMix (const Layer *, int *, int, int, int, int); +int mapIsland (const Layer *, int *, int, int, int, int); +int mapZoomIsland (const Layer *, int *, int, int, int, int); +int mapZoom (const Layer *, int *, int, int, int, int); +int mapAddIsland (const Layer *, int *, int, int, int, int); +int mapRemoveTooMuchOcean (const Layer *, int *, int, int, int, int); +int mapAddSnow (const Layer *, int *, int, int, int, int); +int mapCoolWarm (const Layer *, int *, int, int, int, int); +int mapHeatIce (const Layer *, int *, int, int, int, int); +int mapSpecial (const Layer *, int *, int, int, int, int); +int mapAddMushroomIsland (const Layer *, int *, int, int, int, int); +int mapDeepOcean (const Layer *, int *, int, int, int, int); +int mapBiome (const Layer *, int *, int, int, int, int); +int mapBiomeBE (const Layer *, int *, int, int, int, int); +int mapAddBamboo (const Layer *, int *, int, int, int, int); +int mapRiverInit (const Layer *, int *, int, int, int, int); +int mapBiomeEdge (const Layer *, int *, int, int, int, int); +int mapHills (const Layer *, int *, int, int, int, int); +int mapRiver (const Layer *, int *, int, int, int, int); +int mapSmooth (const Layer *, int *, int, int, int, int); +int mapRareBiome (const Layer *, int *, int, int, int, int); +int mapShore (const Layer *, int *, int, int, int, int); +int mapRiverMix (const Layer *, int *, int, int, int, int); // 1.13 layers -void mapHills113 (const Layer *, int *, int, int, int, int); -void mapOceanTemp (const Layer *, int *, int, int, int, int); -void mapOceanMix (const Layer *, int *, int, int, int, int); +int mapHills113 (const Layer *, int *, int, int, int, int); +int mapOceanTemp (const Layer *, int *, int, int, int, int); +int mapOceanMix (const Layer *, int *, int, int, int, int); // final layer 1:1 -void mapVoronoiZoom (const Layer *, int *, int, int, int, int); +int mapVoronoiZoom (const Layer *, int *, int, int, int, int); #ifdef __cplusplus diff --git a/makefile b/makefile index 7c8ae83..ab14d7f 100644 --- a/makefile +++ b/makefile @@ -2,8 +2,7 @@ CC = gcc AR = ar ARFLAGS = cr override LDFLAGS = -lm -override CFLAGS += -Wall -fwrapv -march=native -#override CFLAGS += -DUSE_SIMD +override CFLAGS += -Wall -fwrapv ifeq ($(OS),Windows_NT) override CFLAGS += -D_WIN32 @@ -13,15 +12,16 @@ else #RM = rm endif -.PHONY : all debug libcubiomes clean +.PHONY : all release debug libcubiomes clean -all: CFLAGS += -O3 -march=native -all: libcubiomes find_quadhuts find_compactbiomes clean +all: release debug: CFLAGS += -DDEBUG -O0 -ggdb3 -debug: find_quadhuts find_compactbiomes clean +debug: libcubiomes +release: CFLAGS += -O3 -march=native +release: libcubiomes find_quadhuts find_compactbiomes -libcubiomes: CFLAGS += -O3 -fPIC +libcubiomes: CFLAGS += -fPIC libcubiomes: layers.o generator.o finders.o util.o $(AR) $(ARFLAGS) libcubiomes.a $^