]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Make server thread-safe
authorElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 31 Mar 2021 13:59:21 +0000 (15:59 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 31 Mar 2021 13:59:21 +0000 (15:59 +0200)
17 files changed:
src/Makefile
src/clientmap.c
src/facecache.c [new file with mode: 0644]
src/facecache.h [new file with mode: 0644]
src/map.c
src/map.h
src/mapgen.c [new file with mode: 0644]
src/mapgen.h [new file with mode: 0644]
src/network.c
src/perlin.c [new file with mode: 0644]
src/perlin.h [new file with mode: 0644]
src/server.c
src/server.h
src/servercommands.c
src/servercommands.h
src/servermap.c
src/servermap.h

index 13da2d5ea6e5cdf623bf6ebd6d8da9e2e2df2d8e..a21289b752b15b69dd27aff0f6e0280fe69b0f8c 100644 (file)
@@ -1,5 +1,5 @@
 COMMON = array.o list.o map.o signal.o util.o types.o node.o
-SERVER = $(COMMON) server.o servercommands.o servermap.o
+SERVER = $(COMMON) server.o servercommands.o servermap.o perlin.o facecache.o mapgen.o
 CLIENT = $(COMMON) client.o clientcommands.o clientmap.o mesh.o scene.o shaders.o
 LIBRARIES = -lpthread -lm
 FLAGS = -g -fmax-errors=4
index 236785b2bd4f2c5801a83292ccd496e823ae3263..5180b0ca0332b34d67f57e795c5c0f24de1c84d1 100644 (file)
@@ -123,7 +123,6 @@ static void *meshgen_thread(void *unused)
                if (*lptr) {
                        pthread_mutex_lock(&meshgen.mtx);
                        MapBlock *block = (*lptr)->key;
-                       block->state = MBS_READY;
                        ListPair *next = (*lptr)->next;
                        free(*lptr);
                        *lptr = next;
@@ -170,9 +169,6 @@ void clientmap_deinit()
 void clientmap_block_changed(MapBlock *block)
 {
        pthread_mutex_lock(&meshgen.mtx);
-       if (block->state != MBS_PROCESSING) {
-               block->state = MBS_PROCESSING;
-               list_put(&meshgen.queue, block, NULL);
-       }
+       list_put(&meshgen.queue, block, NULL);
        pthread_mutex_unlock(&meshgen.mtx);
 }
diff --git a/src/facecache.c b/src/facecache.c
new file mode 100644 (file)
index 0000000..8c81765
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include "array.h"
+#include "facecache.h"
+
+static struct
+{
+       Array positions;
+       u32 size;
+       pthread_mutex_t mtx;
+} facecache;
+
+__attribute((constructor)) static void init_face_cache()
+{
+       facecache.size = 0;
+       facecache.positions = array_create(sizeof(v3s32));
+       v3s32 pos = {0};
+       array_append(&facecache.positions, &pos);
+       pthread_mutex_init(&facecache.mtx, NULL);
+}
+
+__attribute((destructor)) void deinit_face_cache()
+{
+       if (facecache.positions.ptr)
+               free(facecache.positions.ptr);
+       pthread_mutex_destroy(&facecache.mtx);
+}
+
+static void calculate_face_cache(s32 size)
+{
+#define ADDPOS(a, b, c, va, vb, vc) \
+       { \
+               v3s32 pos; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, a)) = va; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, b)) = vb; \
+               *(s32 *) ((char *) &pos + offsetof(v3s32, c)) = vc; \
+               array_append(&facecache.positions, &pos); \
+       }
+#define SQUARES(a, b, c) \
+       for (s32 va = -size + 1; va < size; va++) { \
+               for (s32 vb = -size + 1; vb < size; vb++) { \
+                       ADDPOS(a, b, c, va, vb,  size) \
+                       ADDPOS(a, b, c, va, vb, -size) \
+               } \
+       }
+       SQUARES(x, z, y)
+       SQUARES(x, y, z)
+       SQUARES(z, y, x)
+#undef SQUARES
+#define EDGES(a, b, c) \
+       for (s32 va = -size + 1; va < size; va++) { \
+               ADDPOS(a, b, c, va,  size,  size) \
+               ADDPOS(a, b, c, va,  size, -size) \
+               ADDPOS(a, b, c, va, -size,  size) \
+               ADDPOS(a, b, c, va, -size, -size) \
+       }
+       EDGES(x, y, z)
+       EDGES(z, x, y)
+       EDGES(y, x, z)
+#undef EDGES
+       ADDPOS(x, y, z,  size,  size,  size)
+       ADDPOS(x, y, z,  size,  size, -size)
+       ADDPOS(x, y, z,  size, -size,  size)
+       ADDPOS(x, y, z,  size, -size, -size)
+       ADDPOS(x, y, z, -size,  size,  size)
+       ADDPOS(x, y, z, -size,  size, -size)
+       ADDPOS(x, y, z, -size, -size,  size)
+       ADDPOS(x, y, z, -size, -size, -size)
+#undef ADDPOS
+}
+
+v3s32 get_face(size_t i, v3s32 *base)
+{
+       pthread_mutex_lock(&facecache.mtx);
+       while (facecache.positions.siz <= i)
+               calculate_face_cache(++facecache.size);
+       v3s32 pos = ((v3s32 *) facecache.positions.ptr)[i];
+       pthread_mutex_unlock(&facecache.mtx);
+       if (base) {
+               pos.x += base->x;
+               pos.y += base->y;
+               pos.z += base->z;
+       }
+       return pos;
+}
+
+size_t get_face_count(u32 size)
+{
+       size_t len = 1 + size * 2;
+       return len * len * len;
+}
diff --git a/src/facecache.h b/src/facecache.h
new file mode 100644 (file)
index 0000000..706349c
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _FACECACHE_H_
+#define _FACECACHE_H_
+
+#include <pthread.h>
+#include "types.h"
+
+v3s32 get_face(size_t i, v3s32 *base);
+size_t get_face_count(u32 size);
+
+#endif
index 199cac6c25793c6d25e24d41dfbe94cec3a02839..157c0378654e22ecc4ce33c1d60038761450c543 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -30,6 +30,30 @@ static MapBlock *allocate_block(v3s32 pos)
        return block;
 }
 
+static MapBlock *create_block(MapSector *sector, size_t idx, v3s32 pos)
+{
+       MapBlock *block = allocate_block(pos);
+       array_insert(&sector->blocks, &block, idx);
+       return block;
+}
+
+static bool read_block_data(int fd, MapBlockData data)
+{
+       size_t n_read_total = 0;
+       int n_read;
+
+       while (n_read_total < sizeof(MapBlockData)) {
+               if ((n_read = read(fd, (char *) data + n_read_total, sizeof(MapBlockData) - n_read_total)) == -1) {
+                       perror("read");
+                       return false;
+               }
+
+               n_read_total += n_read;
+       }
+
+       return true;
+}
+
 Map *map_create()
 {
        Map *map = malloc(sizeof(Map));
@@ -113,12 +137,11 @@ MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
        MapBlock *block = NULL;
 
        if (res.success) {
-               MapBlock *rawblock = map_get_block_raw(sector, res.index);
-               if (rawblock->state == MBS_READY || create)
-                       block = rawblock;
+               block = map_get_block_raw(sector, res.index);
+               if (block->state < MBS_READY && ! create)
+                       block = NULL;
        } else if (create) {
-               block = allocate_block(pos);
-               array_insert(&sector->blocks, &block, res.index);
+               block = create_block(sector, res.index, pos);
        }
 
        pthread_rwlock_unlock(&sector->rwlck);
@@ -190,46 +213,23 @@ bool map_deserialize_block(int fd, Map *map, MapBlock **blockptr, bool dummy)
 
        MapBlock *block;
 
-       if (dummy) {
+       if (dummy)
                block = allocate_block(pos);
-       } else {
-               MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, true);
-
-               pthread_rwlock_wrlock(&sector->rwlck);
-               ArraySearchResult res = array_search(&sector->blocks, &pos.y);
-
-               if (res.success) {
-                       block = map_get_block_raw(sector, res.index);
-               } else {
-                       block = allocate_block(pos);
-                       array_insert(&sector->blocks, &block, res.index);
-               }
-
-               pthread_rwlock_unlock(&sector->rwlck);
+       else
+               block = map_get_block(map, pos, true);
 
-               if (res.success)
-                       map_clear_meta(block);
-       }
+       if (block->state != MBS_CREATED)
+               map_clear_meta(block);
 
        pthread_mutex_lock(&block->mtx);
+       block->state = MBS_INITIALIZING;
 
-       bool ret = true;
-       size_t n_read_total = 0;
-       int n_read;
        MapBlockData data;
 
-       while (n_read_total < sizeof(MapBlockData)) {
-               if ((n_read = read(fd, (char *) data + n_read_total, sizeof(MapBlockData) - n_read_total)) == -1) {
-                       perror("read");
-                       ret = false;
-                       break;
-               }
-
-               n_read_total += n_read;
-       }
+       bool success = read_block_data(fd, data);
 
        ITERATE_MAPBLOCK {
-               if (ret) {
+               if (success) {
                        MapNode node = data[x][y][z];
                        node.type = be32toh(node.type);
 
@@ -242,15 +242,16 @@ bool map_deserialize_block(int fd, Map *map, MapBlock **blockptr, bool dummy)
                block->metadata[x][y][z] = list_create(&list_compare_string);
        }
 
+       block->state = MBS_UNSENT;
 
        if (dummy)
                map_free_block(block);
-       else if (blockptr && ret)
+       else if (blockptr && success)
                *blockptr = block;
 
        pthread_mutex_unlock(&block->mtx);
 
-       return ret;
+       return success;
 }
 
 bool map_serialize(FILE *file, Map *map)
@@ -299,7 +300,7 @@ void map_set_node(Map *map, v3s32 pos, MapNode node)
                list_clear(&block->metadata[offset.x][offset.y][offset.z]);
                block->data[offset.x][offset.y][offset.z] = node;
 
-               block->state = MBS_MODIFIED;
+               block->state = MBS_UNSENT;
        }
 }
 
index 3eab330643d1be39fdd4c8a15ac872b7dc4319a9..64d7fbec2eab3693c29aea69ee09837fad8be3ee 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -20,9 +20,10 @@ typedef struct
 typedef enum
 {
        MBS_CREATED,
-       MBS_PROCESSING,
+       MBS_INITIALIZING,
        MBS_READY,
-       MBS_MODIFIED,
+       MBS_UNSENT,
+       MBS_SENDING,
 } MapBlockState;
 
 typedef MapNode MapBlockData[16][16][16];
diff --git a/src/mapgen.c b/src/mapgen.c
new file mode 100644 (file)
index 0000000..9491e4a
--- /dev/null
@@ -0,0 +1,27 @@
+#include "mapgen.h"
+#include "perlin.h"
+
+void mapgen_generate_block(MapBlock *block)
+{
+       for (u8 x = 0; x < 16; x++) {
+               u32 ux = x + block->pos.x * 16 + ((u32) 1 << 31);
+               for (u8 z = 0; z < 16; z++) {
+                       u32 uz = z + block->pos.z * 16 + ((u32) 1 << 31);
+                       s32 height = smooth2d((double) ux / 32.0f, (double) uz / 32.0f, 0, 0) * 16.0f;
+                       for (u8 y = 0; y < 16; y++) {
+                               s32 ay = y + block->pos.y * 16;
+                               Node type;
+                               if (ay > height)
+                                       type = NODE_AIR;
+                               else if (ay == height)
+                                       type = NODE_GRASS;
+                               else if (ay >= height - 4)
+                                       type = NODE_DIRT;
+                               else
+                                       type = NODE_STONE;
+                               block->data[x][y][z] = map_node_create(type);
+                               block->metadata[x][y][z] = list_create(&list_compare_string);
+                       }
+               }
+       }
+}
diff --git a/src/mapgen.h b/src/mapgen.h
new file mode 100644 (file)
index 0000000..8f1b20d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _MAPGEN_H_
+#define _MAPGEN_H_
+
+#include "map.h"
+
+void mapgen_generate_block(MapBlock *block);
+
+#endif
index 5e0ecb881d85f44ebc7896f113bcf1666990b77d..0d29637d3f3796ecbcf6120ab50e382fc3c53bb7 100644 (file)
@@ -8,7 +8,7 @@ bool send_command(Client *client, RemoteCommand cmd)
        return ret;
 }
 
-static void handle_packets(Client *client) {
+static bool handle_packets(Client *client) {
        while (client->state != CS_DISCONNECTED || ! interrupted) {
                struct pollfd pfd = {
                        .fd = client->fd,
@@ -20,7 +20,7 @@ static void handle_packets(Client *client) {
 
                if (pstate == -1) {
                        perror("poll");
-                       return;
+                       break;
                }
 
                if (pstate == 0) {
@@ -29,11 +29,11 @@ static void handle_packets(Client *client) {
                }
 
                if (! (pfd.revents & POLLIN))
-                       return;
+                       return false;
 
                HostCommand command;
                if (! read_u32(client->fd, &command))
-                       return;
+                       break;
 
                CommandHandler *handler = NULL;
 
@@ -45,9 +45,11 @@ static void handle_packets(Client *client) {
                        if (! good)
                                printf("Recieved %s command, but client is in invalid state: %d\n", handler->name, client->state);
                        if (! handler->func(client, good))
-                               return;
+                               break;
                } else {
                        printf("Recieved invalid command %d\n", command);
                }
        }
+
+       return client->state == CS_DISCONNECTED || errno == EINTR;
 }
diff --git a/src/perlin.c b/src/perlin.c
new file mode 100644 (file)
index 0000000..c6d415c
--- /dev/null
@@ -0,0 +1,2 @@
+#include <perlin/perlin.c>
+
diff --git a/src/perlin.h b/src/perlin.h
new file mode 100644 (file)
index 0000000..b328f61
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _PERLIN_H_
+#define _PERLIN_H_
+
+#include <perlin/perlin.h>
+
+#endif
index a4b33c47b1f663e15d295eefb847a28777eca770..d90a558996b615866ab65cb3ebecbb4100eb4ab1 100644 (file)
@@ -12,10 +12,19 @@ Server server;
 
 void server_disconnect_client(Client *client, int flags, const char *detail)
 {
+       ClientState cs = client->state;
        client->state = CS_DISCONNECTED;
 
-       if (client->name && ! (flags & DISCO_NO_REMOVE))
-               list_delete(&server.clients, client->name);
+       if (! (flags & DISCO_NO_REMOVE)) {
+               if (client->name) {
+                       pthread_rwlock_wrlock(&server.players_rwlck);
+                       list_delete(&server.players, client->name);
+                       pthread_rwlock_unlock(&server.players_rwlck);
+               }
+               pthread_rwlock_wrlock(&server.clients_rwlck);
+               list_delete(&server.clients, client);
+               pthread_rwlock_unlock(&server.clients_rwlck);
+       }
 
        if (! (flags & DISCO_NO_MESSAGE))
                printf("Disconnected %s %s%s%s\n", client->name, INBRACES(detail));
@@ -26,27 +35,29 @@ void server_disconnect_client(Client *client, int flags, const char *detail)
        pthread_mutex_lock(&client->mtx);
        close(client->fd);
        pthread_mutex_unlock(&client->mtx);
-}
-
-#include "network.c"
 
-static void *server_reciever_thread(void *clientptr)
-{
-       Client *client = clientptr;
-
-       handle_packets(client);
+       if (! (flags & DISCO_NO_JOIN))
+               pthread_join(client->net_thread, NULL);
 
-       if (client->state != CS_DISCONNECTED)
-               server_disconnect_client(client, DISCO_NO_SEND, "network error");
+       if (cs == CS_ACTIVE)
+               pthread_join(client->map_thread, NULL);
 
        if (client->name != client->address)
                free(client->name);
-
        free(client->address);
 
        pthread_mutex_destroy(&client->mtx);
-
        free(client);
+}
+
+#include "network.c"
+
+static void *server_reciever_thread(void *cli)
+{
+       Client *client = cli;
+
+       if (! handle_packets(client))
+               server_disconnect_client(client, DISCO_NO_SEND | DISCO_NO_JOIN, "network error");
 
        return NULL;
 }
@@ -72,7 +83,11 @@ static void server_accept_client()
        client->name = client->address;
        client->server = &server;
        client->pos = (v3f) {0.0f, 0.0f, 0.0f};
-       pthread_create(&client->thread, NULL, &server_reciever_thread, client);
+       pthread_create(&client->net_thread, NULL, &server_reciever_thread, client);
+
+       pthread_rwlock_wrlock(&server.clients_rwlck);
+       list_put(&server.clients, client, NULL);
+       pthread_rwlock_unlock(&server.clients_rwlck);
 
        printf("Connected %s\n", client->address);
 }
@@ -81,7 +96,10 @@ void server_start(int fd)
 {
        server.sockfd = fd;
        server.map = map_create(NULL);
-       server.clients = list_create(&list_compare_string);
+       pthread_rwlock_init(&server.clients_rwlck, NULL);
+       server.clients = list_create(NULL);
+       pthread_rwlock_init(&server.players_rwlck, NULL);
+       server.players = list_create(&list_compare_string);
 
        FILE *mapfile = fopen("map", "r");
        if (mapfile) {
@@ -98,8 +116,16 @@ void server_start(int fd)
 
        printf("Shutting down\n");
 
-       ITERATE_LIST(&server.clients, pair) server_disconnect_client(pair->value, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
+       pthread_rwlock_wrlock(&server.clients_rwlck);
+       ITERATE_LIST(&server.clients, pair) server_disconnect_client(pair->key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, "");
        list_clear(&server.clients);
+       pthread_rwlock_unlock(&server.clients_rwlck);
+       pthread_rwlock_wrlock(&server.players_rwlck);
+       list_clear(&server.players);
+       pthread_rwlock_unlock(&server.players_rwlck);
+
+       pthread_rwlock_destroy(&server.clients_rwlck);
+       pthread_rwlock_destroy(&server.players_rwlck);
 
        shutdown(server.sockfd, SHUT_RDWR);
        close(server.sockfd);
index 8cdfcee6eb0d0a59e42fba1dcab7547867a7157d..0048c05de8b300a15e2e0b801111c1a39e92b82d 100644 (file)
 typedef struct
 {
        int sockfd;
+       pthread_rwlock_t clients_rwlck;
        List clients;
+       pthread_rwlock_t players_rwlck;
+       List players;
        Map *map;
 } Server;
 
@@ -24,7 +27,8 @@ typedef struct Client
        char *address;
        char *name;
        Server *server;
-       pthread_t thread;
+       pthread_t net_thread;
+       pthread_t map_thread;
        v3f pos;
 } Client;
 
@@ -33,6 +37,7 @@ typedef enum
        DISCO_NO_REMOVE = 0x01,
        DISCO_NO_SEND = 0x02,
        DISCO_NO_MESSAGE = 0x04,
+       DISCO_NO_JOIN = 0x08,
 } DiscoFlag;
 
 void server_disconnect_client(Client *client, int flags, const char *detail);
index f8b4dd762ce3df63a9b506cb798f7b4058f2684d..328627774f2901cfe7c5d8662308b2d04a12e25d 100644 (file)
@@ -23,7 +23,9 @@ static bool auth_handler(Client *client, bool good)
                return true;
        }
 
-       u8 success = list_put(&client->server->clients, name, client);
+       pthread_rwlock_wrlock(&client->server->players_rwlck);
+       u8 success = list_put(&client->server->players, name, client);
+       pthread_rwlock_unlock(&client->server->players_rwlck);
 
        printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name);
 
@@ -60,23 +62,6 @@ static bool setnode_handler(Client *client, bool good)
        return true;
 }
 
-static bool kick_handler(Client *client, bool good)
-{
-       char *target_name = read_string(client->fd, NAME_MAX);
-
-       if (! target_name)
-               return false;
-
-       if (good) {
-               Client *target = list_get(&client->server->clients, target_name);
-               if (target)
-                       server_disconnect_client(target, 0, "kicked");
-       }
-
-       free(target_name);
-       return true;
-}
-
 static bool pos_handler(Client *client, bool good)
 {
        v3f pos;
@@ -95,6 +80,5 @@ CommandHandler command_handlers[SERVER_COMMAND_COUNT] = {
        {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE},
        {&auth_handler, "AUTH", CS_CREATED},
        {&setnode_handler, "SETNODE", CS_ACTIVE},
-       {&kick_handler, "KICK", CS_ACTIVE},
        {&pos_handler, "POS", CS_ACTIVE},
 };
index 5e7c70202cfff5a1c17a29b080a213840f780057..e3c2f9f098de098289a83f466ead0ba65a20c0c2 100644 (file)
@@ -7,7 +7,6 @@ typedef enum
        SC_DISCONNECT,
        SC_AUTH,
        SC_SETNODE,
-       SC_KICK,
        SC_POS,
        SERVER_COMMAND_COUNT,
 } ServerCommand;
index fa4a1bb029b92b1d6289262bbd7f48d78bb13991..b33ef696b7b3586fa84d919547d8595f80834a7d 100644 (file)
@@ -2,42 +2,14 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-#include <perlin/perlin.h>
+#include "facecache.h"
+#include "mapgen.h"
+#include "map.h"
 #include "servermap.h"
 
-int seed = 0;
-static Server *server = NULL;
+static size_t max_blocks;
 
-static void generate_block(MapBlock *block)
-{
-       pthread_mutex_lock(&block->mtx);
-       if (block->state != MBS_CREATED)
-               return;
-       block->state = MBS_PROCESSING;
-       pthread_mutex_unlock(&block->mtx);
-       for (u8 x = 0; x < 16; x++) {
-               u32 ux = x + block->pos.x * 16 + ((u32) 1 << 31);
-               for (u8 z = 0; z < 16; z++) {
-                       u32 uz = z + block->pos.z * 16 + ((u32) 1 << 31);
-                       s32 height = smooth2d((double) ux / 32.0f, (double) uz / 32.0f, 0, seed) * 16.0f;
-                       for (u8 y = 0; y < 16; y++) {
-                               s32 ay = y + block->pos.y * 16;
-                               Node type;
-                               if (ay > height)
-                                       type = NODE_AIR;
-                               else if (ay == height)
-                                       type = NODE_GRASS;
-                               else if (ay >= height - 4)
-                                       type = NODE_DIRT;
-                               else
-                                       type = NODE_STONE;
-                               block->data[x][y][z] = map_node_create(type);
-                               block->metadata[x][y][z] = list_create(&list_compare_string);
-                       }
-               }
-       }
-       block->state = MBS_READY;
-}
+static Server *server = NULL;
 
 typedef struct
 {
@@ -45,6 +17,17 @@ typedef struct
        size_t size;
 } MapBlockBuffer;
 
+static void generate_block(MapBlock *block)
+{
+       pthread_mutex_lock(&block->mtx);
+       if (block->state == MBS_CREATED) {
+               block->state = MBS_INITIALIZING;
+               mapgen_generate_block(block);
+               block->state = MBS_UNSENT;
+       }
+       pthread_mutex_unlock(&block->mtx);
+}
+
 static void serialize_block(Client *client, MapBlock *block)
 {
        MapBlockBuffer *buffer = block->extra;
@@ -68,104 +51,56 @@ static void serialize_block(Client *client, MapBlock *block)
 static void send_block(MapBlock *block)
 {
        pthread_mutex_lock(&block->mtx);
-       block->state = MBS_READY;
-       // ToDo: only send to near clients
-       ITERATE_LIST(&server->clients, pair) {
-               if (block->state != MBS_READY)
-                       break;
-               Client *client = pair->value;
-               if (client->state == CS_ACTIVE)
-                       serialize_block(client, block);
-       }
-       pthread_mutex_unlock(&block->mtx);
-}
-
-#define RANGE 3
-#define POS_CACHE_COUNT ((1 + RANGE * 2) * (1 + RANGE * 2) * (1 + RANGE * 2))
-static size_t pos_chache_count = POS_CACHE_COUNT;
-static v3s32 pos_cache[POS_CACHE_COUNT];
-
-static void init_pos_cache()
-{
-       size_t i = -1;
-#define ADDPOS(a, b, c, va, vb, vc) \
-       *(s32 *) ((char *) &pos_cache[++i] + offsetof(v3s32, a)) = va; \
-       *(s32 *) ((char *) &pos_cache[i] + offsetof(v3s32, b)) = vb; \
-       *(s32 *) ((char *) &pos_cache[i] + offsetof(v3s32, c)) = vc;
-       ADDPOS(x, y, z, 0, 0, 0)
-       for (s32 l = 1; l <= RANGE ; l++) {
-#define SQUARES(a, b, c) \
-               for (s32 va = -l + 1; va < l; va++) { \
-                       for (s32 vb = -l + 1; vb < l; vb++) { \
-                               ADDPOS(a, b, c, va, vb,  l) \
-                               ADDPOS(a, b, c, va, vb, -l) \
-                       } \
+       if (block->state == MBS_UNSENT) {
+               block->state = MBS_SENDING;
+               if (block->extra) {
+                       free(((MapBlockBuffer *) block->extra)->ptr);
+                       free(block->extra);
+                       block->extra = NULL;
                }
-               SQUARES(x, z, y)
-               SQUARES(x, y, z)
-               SQUARES(z, y, x)
-#undef SQUARES
-#define EDGES(a, b, c) \
-               for (s32 va = -l + 1; va < l; va++) { \
-                       ADDPOS(a, b, c, va,  l,  l) \
-                       ADDPOS(a, b, c, va,  l, -l) \
-                       ADDPOS(a, b, c, va, -l,  l) \
-                       ADDPOS(a, b, c, va, -l, -l) \
+               // ToDo: only send to near clients
+               pthread_rwlock_rdlock(&server->players_rwlck);
+               ITERATE_LIST(&server->players, pair) {
+                       if (block->state != MBS_SENDING)
+                               break;
+                       serialize_block(pair->value, block);
                }
-               EDGES(x, y, z)
-               EDGES(z, x, y)
-               EDGES(y, x, z)
-#undef EDGES
-               ADDPOS(x, y, z,  l,  l,  l)
-               ADDPOS(x, y, z,  l,  l, -l)
-               ADDPOS(x, y, z,  l, -l,  l)
-               ADDPOS(x, y, z,  l, -l, -l)
-               ADDPOS(x, y, z, -l,  l,  l)
-               ADDPOS(x, y, z, -l,  l, -l)
-               ADDPOS(x, y, z, -l, -l,  l)
-               ADDPOS(x, y, z, -l, -l, -l)
-#undef ADDPOS
+               pthread_rwlock_unlock(&server->players_rwlck);
+               if (block->state == MBS_SENDING)
+                       block->state = MBS_READY;
        }
+       pthread_mutex_unlock(&block->mtx);
 }
 
-static void send_blocks(Client *client, bool init)
+static void send_blocks(Client *client)
 {
        v3s32 pos = map_node_to_block_pos((v3s32) {client->pos.x, client->pos.y, client->pos.z}, NULL);
-       for (size_t i = 0; i < pos_chache_count; i++) {
-               MapBlock *block = map_get_block(client->server->map, (v3s32) {pos.x + pos_cache[i].x, pos.y + pos_cache[i].y, pos.z + pos_cache[i].z}, ! init);
-               if (init) {
-                       if (block)
-                               serialize_block(client, block);
-               } else switch (block->state) {
+       for (size_t i = 0; i < max_blocks; i++) {
+               MapBlock *block = map_get_block(client->server->map, get_face(i, &pos), true);
+               switch (block->state) {
                case MBS_CREATED:
                        generate_block(block);
                        __attribute__ ((fallthrough));
-               case MBS_MODIFIED:
-                       if (block->extra) {
-                               free(((MapBlockBuffer *) block->extra)->ptr);
-                               free(block->extra);
-                               block->extra = NULL;
-                       }
+               case MBS_UNSENT:
                        send_block(block);
                        __attribute__ ((fallthrough));
-               case MBS_PROCESSING:
-                       i = -1;
-                       sched_yield();
-                       __attribute__ ((fallthrough));
+               case MBS_INITIALIZING:
+               case MBS_SENDING:
+                       return;
                case MBS_READY:
                        break;
                }
        }
 }
 
-static void *block_send_thread(void *cli)
+static void *map_thread(void *cli)
 {
        Client *client = cli;
 
-       send_blocks(client, true);
-
-       while (client->state != CS_DISCONNECTED)
-               send_blocks(client, false);
+       while (client->state != CS_DISCONNECTED) {
+               send_blocks(client);
+               sched_yield();
+       }
 
        return NULL;
 }
@@ -173,13 +108,10 @@ static void *block_send_thread(void *cli)
 void servermap_init(Server *srv)
 {
        server = srv;
-       init_pos_cache();
+       max_blocks = get_face_count(3);
 }
 
 void servermap_add_client(Client *client)
 {
-       pthread_t thread;
-       pthread_create(&thread, NULL, &block_send_thread, client);
+       pthread_create(&client->map_thread, NULL, &map_thread, client);
 }
-
-#include <perlin/perlin.c>
index c40b9f900991b5a6ed26f7eb9caf628a1a9afef3..7fc27f6a56c928e239820e92b413bc657c78b7e3 100644 (file)
@@ -1,8 +1,7 @@
-#ifndef _MAPGEN_H_
-#define _MAPGEN_H_
+#ifndef _SERVERMAP_H_
+#define _SERVERMAP_H_
 
 #include "server.h"
-#include "map.h"
 
 void servermap_init(Server *srv);