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 $^