]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Add vulcano generation
authorElias Fleckenstein <eliasfleckenstein@web.de>
Mon, 23 Aug 2021 11:47:58 +0000 (13:47 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Mon, 23 Aug 2021 11:47:58 +0000 (13:47 +0200)
src/client/client_node.c
src/client/client_player.c
src/node.c
src/node.h
src/perlin.h
src/server/biomes.c
src/server/biomes.h
src/server/mapgen.c
textures/lava.png [new file with mode: 0644]
textures/lava_nt.png [new file with mode: 0644]
textures/vulcano_stone.png [new file with mode: 0644]

index fba9d559f6b337fa9f242f4e6bc5df0fb3ecc505..de1ed1ba95f7c3479a99483a6a2b347a33c7e269 100644 (file)
@@ -98,6 +98,18 @@ ClientNodeDefintion client_node_definitions[NODE_UNLOADED] = {
                .visibility = NV_TRANSPARENT,
                .render = NULL,
        },
+       // lava
+       {
+               .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/lava.png"),
+               .visibility = NV_TRANSPARENT,
+               .render = NULL,
+       },
+       // vulcano_stone
+       {
+               .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/vulcano_stone.png"),
+               .visibility = NV_SOLID,
+               .render = NULL,
+       },
 };
 
 void client_node_init()
index 6314ca7a066fa93783b20273979e6e05eb69883f..a94ccef225eeadc157fc9a3722e1ee60200081fc 100644 (file)
@@ -74,7 +74,7 @@ static bool can_jump()
 // ClientPlayer singleton constructor
 void client_player_init()
 {
-       client_player.pos = (v3f64) {0.0, 48.0, 0.0};
+       client_player.pos = (v3f64) {-2500.0, 48.0, -2000.0};
        client_player.velocity = (v3f64) {0.0, 0.0, 0.0};
        client_player.box = (aabb3f64) {{-0.3, 0.0, -0.3}, {0.3, 1.75, 0.3}};
        client_player.yaw = client_player.pitch = 0.0f;
index c42fac21a9c51b74c506bcc3256488a7033f6e52..ac94ea7259128ff732110555b1a131296d18656b 100644 (file)
@@ -66,4 +66,18 @@ NodeDefintion node_definitions[NODE_UNLOADED] = {
                .serialize = NULL,
                .deserialize = NULL,
        },
+       // lava
+       {
+               .solid = false,
+               .create = NULL,
+               .serialize = NULL,
+               .deserialize = NULL,
+       },
+       // vulcanostone
+       {
+               .solid = true,
+               .create = NULL,
+               .serialize = NULL,
+               .deserialize = NULL,
+       },
 };
index 07afbaaf08ba5bf9c6fa5c2124743e3ff311e2c7..626b5d79403bfea216c614496c0f3dbf12f3e7de 100644 (file)
@@ -15,6 +15,8 @@ typedef enum
        NODE_WOOD,
        NODE_SAND,
        NODE_WATER,
+       NODE_LAVA,
+       NODE_VULCANO_STONE,
        NODE_UNLOADED,          // Used for nodes in unloaded blocks
 } Node;
 
index 882a55b8cd5567df7a8baecc4276429d967dbb17..c1af34be0b39bf4726b63dddd6da5b7ed763cc38 100644 (file)
@@ -20,6 +20,10 @@ typedef enum
        SO_PINE,
        SO_PINE_HEIGHT,
        SO_PINE_BRANCH,
+       SO_VULCANO,
+       SO_VULCANO_HEIGHT,
+       SO_VULCANO_STONE,
+       SO_VULCANO_CRATER_TOP,
 } SeedOffset;
 
 extern int seed;
index 2c92097b0115b9fcd57facb6fa140dbb772b2b19..1bdde8906964ed9dcc7b87b164aa3ed4e1d312e5 100644 (file)
@@ -3,18 +3,37 @@
 #include "server/mapgen.h"
 #include "server/server_map.h"
 #include "util.h"
-#define NUM_BIOMES 3
 
-static s32 height_mountain(v3s32 pos, f64 factor, s32 height)
+Biome get_biome(v2s32 pos, f64 *factor)
 {
-       return pow((height + 96) * pow(((smooth2d(U32(pos.x) / 48.0, U32(pos.z) / 48.0, 0, seed + SO_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), factor), 1.0 / (factor + 1.0)) - 96;
+       for (Biome i = 0; i < BIOME_COUNT; i++) {
+               BiomeDef *def = &biomes[i];
+               f64 f = def->probability == 1.0 ? 1.0 : (smooth2d(U32(pos.x) / def->threshold, U32(pos.y) / def->threshold, 0, seed + def->offset) * 0.5 - 0.5 + def->probability) / def->probability;
+
+               if (f > 0.0) {
+                       if (factor)
+                               *factor = f;
+                       return i;
+               }
+       }
+
+       return BIOME_COUNT;
+}
+
+// mountain biome
+
+static s32 height_mountain(v2s32 pos, f64 factor, s32 height, unused void *row_data, unused void *block_data)
+{
+       return pow((height + 96) * pow(((smooth2d(U32(pos.x) / 48.0, U32(pos.y) / 48.0, 0, seed + SO_MOUNTAIN_HEIGHT) + 1.0) * 256.0 + 128.0), factor), 1.0 / (factor + 1.0)) - 96;
 }
 
-static Node generate_mountain(unused v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks)
+static Node generate_mountain(unused v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, unused void *row_data, unused void *block_data)
 {
        return diff <= 0 ? NODE_STONE : NODE_AIR;
 }
 
+// ocean biome
+
 typedef enum
 {
        OL_BEACH_EDGE,
@@ -26,11 +45,29 @@ typedef enum
 
 static f64 ocean_level_start[OL_COUNT] = {
        0.0,
+       0.1,
        0.2,
-       0.3,
-       0.8,
+       0.5,
 };
 
+typedef struct
+{
+       bool has_vulcano;
+       v2s32 vulcano_pos;
+} OceanBlockData;
+
+typedef struct
+{
+       bool vulcano;
+       bool vulcano_crater;
+       s32 vulcano_height;
+       s32 vulcano_crater_top;
+       Node vulcano_stone;
+} OceanRowData;
+
+static const f64 vulcano_radius = 256.0;
+static const f64 vulcano_block_offset = vulcano_radius * 2.0 / MAPBLOCK_SIZE;
+
 static OceanLevel get_ocean_level(f64 factor)
 {
        if (factor >= ocean_level_start[OL_DEEP_OCEAN])
@@ -43,11 +80,6 @@ static OceanLevel get_ocean_level(f64 factor)
        return OL_BEACH_EDGE;
 }
 
-static s32 mix(s32 a, s32 b, f64 f)
-{
-       return (a * (1.0 - f) + b * f);
-}
-
 static f64 get_ocean_level_factor(f64 factor, OceanLevel level)
 {
        f64 start, end;
@@ -57,20 +89,73 @@ static f64 get_ocean_level_factor(f64 factor, OceanLevel level)
        return (factor - start) / (end - start);
 }
 
-static s32 height_ocean(unused v3s32 pos, f64 factor, s32 height)
+static bool is_vulcano(v2s32 pos)
+{
+       f64 factor;
+       return smooth2d(U32(pos.x), U32(pos.y), 0, seed + SO_VULCANO) > 0.0 && get_biome((v2s32) {pos.x * MAPBLOCK_SIZE, pos.y * MAPBLOCK_SIZE}, &factor) == BIOME_OCEAN && get_ocean_level(factor) == OL_DEEP_OCEAN;
+}
+
+static bool find_near_vulcano(v2s32 pos, v2s32 *result)
+{
+       f64 x = pos.x / vulcano_block_offset;
+       f64 z = pos.y / vulcano_block_offset;
+
+       s32 lx, lz;
+       lx = floor(x);
+       lz = floor(z);
+
+       s32 hx, hz;
+       hx = ceil(x);
+       hz = ceil(z);
+
+       for (s32 ix = lx; ix <= hx; ix++) {
+               for (s32 iz = lz; iz <= hz; iz++) {
+                       v2s32 vulcano_pos = {ix * 32, iz * 32};
+
+                       if (is_vulcano(vulcano_pos)) {
+                               *result = vulcano_pos;
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+static f64 mix(f64 a, f64 b, f64 f)
+{
+       return (a * (1.0 - f) + b * f);
+}
+
+static inline f64 min(f64 a, f64 b)
+{
+       return a < b ? a : b;
+}
+
+static inline f64 max(f64 a, f64 b)
+{
+       return a > b ? a : b;
+}
+
+static f64 distance(v2s32 a, v2s32 b)
+{
+       return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
+}
+
+static s32 calculate_ocean_floor(f64 factor, s32 height)
 {
        switch (get_ocean_level(factor)) {
                case OL_BEACH_EDGE:
-                       return mix(height + 1, 0, get_ocean_level_factor(factor, OL_BEACH_EDGE));
+                       return mix(height + 1, 0, pow(get_ocean_level_factor(factor, OL_BEACH_EDGE), 0.8));
 
                case OL_BEACH:
                        return 0;
 
                case OL_OCEAN:
-                       return mix(0, -10, get_ocean_level_factor(factor, OL_OCEAN));
+                       return mix(0, -10, pow(get_ocean_level_factor(factor, OL_OCEAN), 0.5));
 
                case OL_DEEP_OCEAN:
-                       return mix(-10, -50, get_ocean_level_factor(factor, OL_DEEP_OCEAN));
+                       return mix(-10, -50, pow(get_ocean_level_factor(factor, OL_DEEP_OCEAN), 0.5));
 
                default:
                        break;
@@ -79,24 +164,83 @@ static s32 height_ocean(unused v3s32 pos, f64 factor, s32 height)
        return height;
 }
 
-static Node generate_ocean(unused v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks)
+static void preprocess_block_ocean(MapBlock *block, unused List *changed_blocks, void *block_data)
 {
-       if (diff <= -5)
-               return NODE_STONE;
-       else if (diff <= 0)
-               return NODE_SAND;
-       else if (pos.y <= 0)
-               return NODE_WATER;
+       OceanBlockData *data = block_data;
+
+       v2s32 vulcano_pos;
+       if ((data->has_vulcano = find_near_vulcano((v2s32) {block->pos.x, block->pos.z}, &vulcano_pos)))
+               data->vulcano_pos = (v2s32) {vulcano_pos.x * MAPBLOCK_SIZE, vulcano_pos.y * MAPBLOCK_SIZE};
+}
+
+static void preprocess_row_ocean(v2s32 pos, unused s32 height, unused f64 factor, void *row_data, void *block_data)
+{
+       OceanRowData *rdata = row_data;
+       OceanBlockData *bdata = block_data;
+       rdata->vulcano = false;
+
+       if (bdata->has_vulcano) {
+               f64 dist = distance(pos, bdata->vulcano_pos);
+
+               if (dist < vulcano_radius) {
+                       f64 crater_factor = pow(asin(1.0 - dist / vulcano_radius), 2.0);
+                       f64 vulcano_height = (pnoise2d(U32(pos.x) / 100.0, U32(pos.y) / 100.0, 0.2, 2, seed + SO_VULCANO_HEIGHT) * 0.5 + 0.5) * 128.0 * crater_factor + 1.0 - 30.0;
+                       bool is_crater = vulcano_height > 0;
+
+                       if (! is_crater)
+                               vulcano_height = min(vulcano_height + 5.0, 0.0);
+
+                       if (vulcano_height < 0)
+                               vulcano_height *= 2.0;
+
+                       rdata->vulcano = true;
+                       rdata->vulcano_crater = is_crater;
+                       rdata->vulcano_height = floor(vulcano_height + 0.5);
+                       rdata->vulcano_crater_top = 50 + floor((pnoise2d(U32(pos.x) / 3.0, U32(pos.y) / 3.0, 0.0, 1, seed + SO_VULCANO_CRATER_TOP) * 0.5 + 0.5) * 3.0 + 0.5);
+                       rdata->vulcano_stone = is_crater ? ((pnoise2d(U32(pos.x) / 16.0, U32(pos.y) / 16.0, 0.85, 3, seed + SO_VULCANO_STONE) * 0.5 + 0.5) * crater_factor > 0.4 ? NODE_VULCANO_STONE : NODE_STONE) : NODE_SAND;
+               }
+       }
+}
+
+static s32 height_ocean(unused v2s32 pos, f64 factor, s32 height, void *row_data, unused void *block_data)
+{
+       OceanRowData *rdata = row_data;
+       s32 ocean_floor = calculate_ocean_floor(factor, height);
+
+       return rdata->vulcano ? max(ocean_floor, rdata->vulcano_height) : ocean_floor;
+}
+
+static Node generate_ocean(v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, unused List *changed_blocks, void *row_data, unused void *block_data)
+{
+       OceanRowData *rdata = row_data;
+
+       if (rdata->vulcano && rdata->vulcano_crater) {
+               if (diff <= -5)
+                       return pos.y <= 45 ? NODE_LAVA : NODE_AIR;
+               else if (diff <= 0)
+                       return pos.y <= rdata->vulcano_crater_top ? rdata->vulcano_stone : NODE_AIR;
+               else
+                       return NODE_AIR;
+       } else {
+               if (diff <= -5)
+                       return NODE_STONE;
+               else if (diff <= 0)
+                       return NODE_SAND;
+               else if (pos.y <= 0)
+                       return NODE_WATER;
+       }
 
        return NODE_AIR;
 }
 
-static s32 height_hills(unused v3s32 pos, unused f64 factor, s32 height)
+// hills biome
+
+static s32 height_hills(unused v2s32 pos, unused f64 factor, s32 height, unused void *row_data, unused void *block_data)
 {
        return height;
 }
 
-static Node generate_hills(v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, List *changed_blocks)
+static Node generate_hills(v3s32 pos, s32 diff, unused f64 wetness, unused f64 temperature, unused f64 factor, unused MapBlock *block, List *changed_blocks, unused void *row_data, unused void *block_data)
 {
        if (diff == 2 && smooth2d(U32(pos.x), U32(pos.z), 0, seed + SO_BOULDER_CENTER) > 0.999) {
                for (s8 bx = -1; bx <= 1; bx++) {
@@ -120,39 +264,42 @@ static Node generate_hills(v3s32 pos, s32 diff, unused f64 wetness, unused f64 t
        return NODE_AIR;
 }
 
-static BiomeDef biomes[NUM_BIOMES] = {
+BiomeDef biomes[BIOME_COUNT] = {
        {
                .probability = 0.2,
                .offset = SO_MOUNTAIN,
+               .threshold = 1024.0,
+               .snow = true,
                .height = &height_mountain,
                .generate = &generate_mountain,
+               .block_data_size = 0,
+               .preprocess_block = NULL,
+               .row_data_size = 0,
+               .preprocess_row = NULL,
        },
        {
                .probability = 0.2,
                .offset = SO_OCEAN,
+               .threshold = 2048.0,
+               .snow = false,
                .height = &height_ocean,
                .generate = &generate_ocean,
+               .block_data_size = sizeof(OceanBlockData),
+               .preprocess_block = &preprocess_block_ocean,
+               .row_data_size = sizeof(OceanRowData),
+               .preprocess_row = &preprocess_row_ocean,
+
        },
        {
                .probability = 1.0,
                .offset = SO_NONE,
+               .threshold = 0.0,
+               .snow = true,
                .height = &height_hills,
                .generate = &generate_hills,
+               .block_data_size = 0,
+               .preprocess_block = NULL,
+               .row_data_size = 0,
+               .preprocess_row = NULL,
        },
 };
-
-BiomeDef *get_biome(v3s32 pos, f64 *factor)
-{
-       for (int i = 0; i < NUM_BIOMES; i++) {
-               BiomeDef *def = &biomes[i];
-               f64 f = (smooth2d(U32(pos.x) / 1024.0, U32(pos.z) / 1024.0, 0, seed + def->offset) * 0.5 - 0.5 + def->probability) / def->probability;
-
-               if (f > 0.0) {
-                       if (factor)
-                               *factor = f;
-                       return def;
-               }
-       }
-
-       return NULL;
-}
index d436c068bb8f11ee9a901876a85dac2d0aa15521..415f0ce022d3a7673431093d72c162c484955eed 100644 (file)
@@ -5,14 +5,30 @@
 #include "map.h"
 #include "perlin.h"
 
+typedef enum
+{
+       BIOME_MOUNTAIN,
+       BIOME_OCEAN,
+       BIOME_HILLS,
+       BIOME_COUNT,
+} Biome;
+
 typedef struct
 {
        f64 probability;
        SeedOffset offset;
-       s32 (*height)(v3s32 pos, f64 factor, s32 height);
-       Node (*generate)(v3s32 pos, s32 diff, f64 wetness, f64 temperature, f64 factor, MapBlock *block, List *changed_blocks);
+       f64 threshold;
+       bool snow;
+       s32 (*height)(v2s32 pos, f64 factor, s32 height, void *row_data, void *block_data);
+       Node (*generate)(v3s32 pos, s32 diff, f64 wetness, f64 temperature, f64 factor, MapBlock *block, List *changed_blocks, void *row_data, void *block_data);
+       size_t block_data_size;
+       void (*preprocess_block)(MapBlock *block, List *changed_blocks, void *block_data);
+       size_t row_data_size;
+       void (*preprocess_row)(v2s32 pos, s32 height, f64 factor, void *row_data, void *block_data);
 } BiomeDef;
 
-BiomeDef *get_biome(v3s32 pos, f64 *factor);
+extern BiomeDef biomes[BIOME_COUNT];
+
+Biome get_biome(v2s32 pos, f64 *factor);
 
 #endif
index 04f4f57adff08f7ab4363d63a7153263088d38ae..b9c7e97c3122099c01636da1534e29184ce810fc 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <math.h>
+#include <stdlib.h>
 #include "environment.h"
 #include "perlin.h"
 #include "server/biomes.h"
@@ -24,32 +25,48 @@ void mapgen_generate_block(MapBlock *block, List *changed_blocks)
        MapBlockExtraData *extra = block->extra;
 
        v3s32 block_node_pos = {block->pos.x * MAPBLOCK_SIZE, block->pos.y * MAPBLOCK_SIZE, block->pos.z * MAPBLOCK_SIZE};
-       v3s32 pos;
+
+       char *block_data[BIOME_COUNT] = {NULL};
+       bool preprocessed_block[BIOME_COUNT];
 
        for (u8 x = 0; x < MAPBLOCK_SIZE; x++) {
-               pos.x = block_node_pos.x + x;
+               s32 pos_x = block_node_pos.x + x;
 
                for (u8 z = 0; z < MAPBLOCK_SIZE; z++) {
-                       pos.z = block_node_pos.z + z;
+                       v2s32 pos_horizontal = {pos_x, block_node_pos.z + z};
+
+                       s32 height = pnoise2d(U32(pos_horizontal.x) / 32.0, U32(pos_horizontal.y) / 32.0, 0.45, 5, seed + SO_HEIGHT) * 16.0 + 32;
+
+                       f64 factor;
+                       Biome biome = get_biome(pos_horizontal, &factor);
+                       BiomeDef *biome_def = &biomes[biome];
+
+                       if (biome_def->block_data_size > 0 && ! block_data[biome])
+                               block_data[biome] = malloc(biome_def->block_data_size);
 
-                       s32 height = pnoise2d(U32(pos.x) / 32.0, U32(pos.z) / 32.0, 0.45, 5, seed + SO_HEIGHT) * 16.0 + 32;
+                       if (biome_def->preprocess_block && ! preprocessed_block[biome]) {
+                               biome_def->preprocess_block(block, changed_blocks, block_data[biome]);
+                               preprocessed_block[biome] = true;
+                       }
+
+                       char row_data[biome_def->row_data_size];
 
-                       f64 biome_factor;
-                       BiomeDef *biome_def = get_biome(pos, &biome_factor);
+                       if (biome_def->preprocess_row)
+                               biome_def->preprocess_row(pos_horizontal, height, factor, row_data, block_data[biome]);
 
-                       height = biome_def->height(pos, biome_factor, height);
+                       height = biome_def->height(pos_horizontal, factor, height, row_data, block_data[biome]);
 
                        for (u8 y = 0; y < MAPBLOCK_SIZE; y++) {
-                               pos.y = block_node_pos.y + y;
+                               v3s32 pos = {pos_horizontal.x, block_node_pos.y + y, pos_horizontal.y};
 
                                f64 wetness = get_wetness(pos);
                                f64 temperature = get_temperature(pos);
 
                                s32 diff = pos.y - height;
 
-                               Node node = biome_def->generate(pos, diff, wetness, temperature, biome_factor, block, changed_blocks);
+                               Node node = biome_def->generate(pos, diff, wetness, temperature, factor, block, changed_blocks, row_data, block_data[biome]);
 
-                               if (diff <= 1 && temperature < 0.0 && node == NODE_AIR)
+                               if (biome_def->snow && diff <= 1 && temperature < 0.0 && node == NODE_AIR)
                                        node = NODE_SNOW;
 
                                pthread_mutex_lock(&block->mtx);
@@ -61,4 +78,9 @@ void mapgen_generate_block(MapBlock *block, List *changed_blocks)
                        }
                }
        }
+
+       for (Biome i = 0; i < BIOME_COUNT; i++) {
+               if (block_data[i])
+                       free(block_data[i]);
+       }
 }
diff --git a/textures/lava.png b/textures/lava.png
new file mode 100644 (file)
index 0000000..a88d91d
Binary files /dev/null and b/textures/lava.png differ
diff --git a/textures/lava_nt.png b/textures/lava_nt.png
new file mode 100644 (file)
index 0000000..1a0bdc5
Binary files /dev/null and b/textures/lava_nt.png differ
diff --git a/textures/vulcano_stone.png b/textures/vulcano_stone.png
new file mode 100644 (file)
index 0000000..530fd34
Binary files /dev/null and b/textures/vulcano_stone.png differ