]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Implement node breaking
authorElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 20 Apr 2022 16:07:46 +0000 (18:07 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Wed, 20 Apr 2022 16:07:46 +0000 (18:07 +0200)
32 files changed:
deps/dragonstd
src/CMakeLists.txt
src/client/client_config.c
src/client/client_config.h
src/client/client_inventory.c
src/client/client_item.c
src/client/client_item.h
src/client/client_player.c
src/client/client_player.h
src/client/client_terrain.c
src/client/client_terrain.h
src/client/facedir.c [new file with mode: 0644]
src/client/facedir.h [new file with mode: 0644]
src/client/input.c
src/client/input.h
src/client/interact.c
src/client/interact.h
src/client/terrain_gfx.c
src/client/window.c
src/dig.h [new file with mode: 0644]
src/item.c
src/item.h
src/node.c
src/node.h
src/server/server.c
src/server/server_config.c
src/server/server_item.c [new file with mode: 0644]
src/server/server_item.h [new file with mode: 0644]
src/server/server_player.c
src/server/server_player.h
src/terrain.c
src/types.def

index d439328eed1446e6869a1fd23fe5c0a99350806d..8878e826fa3e7b1231e652fc13d11c7a61629d13 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d439328eed1446e6869a1fd23fe5c0a99350806d
+Subproject commit 8878e826fa3e7b1231e652fc13d11c7a61629d13
index 4df3b80b7446aed709f266b102208a115a55e836..ba84911f2ee4bd814546d698feb3e581a9b62161 100644 (file)
@@ -103,6 +103,7 @@ add_executable(dragonblocks
        client/cube.c
        client/debug_menu.c
        client/facecache.c
+       client/facedir.c
        client/font.c
        client/frustum.c
        client/game.c
@@ -142,6 +143,7 @@ add_executable(dragonblocks_server
        server/schematic.c
        server/server.c
        server/server_config.c
+       server/server_item.c
        server/server_player.c
        server/server_terrain.c
        server/terrain_gen.c
index be0d221c5abfa427fb3c155dbcc59933383ddcf8..cc49c97b19a295d6829e4ff3c52c183731be8393 100644 (file)
@@ -7,10 +7,10 @@ struct ClientConfig client_config = {
        .view_distance = 255.0,
        .vsync = true,
        .meshgen_threads = 4,
+       .swap_mouse_buttons = true,
 };
 
-#define NUM_CONFIG_ENTRIES 5
-static ConfigEntry config_entries[NUM_CONFIG_ENTRIES] = {
+static ConfigEntry config_entries[] = {
        {
                .type = CONFIG_UINT,
                .key = "antialiasing",
@@ -36,14 +36,19 @@ static ConfigEntry config_entries[NUM_CONFIG_ENTRIES] = {
                .key = "meshgen_threads",
                .value = &client_config.meshgen_threads,
        },
+       {
+               .type = CONFIG_BOOL,
+               .key = "swap_mouse_buttons",
+               .value = &client_config.meshgen_threads,
+       },
 };
 
 __attribute__((constructor)) static void client_config_init()
 {
-       config_read("client.conf", config_entries, NUM_CONFIG_ENTRIES);
+       config_read("client.conf", config_entries, sizeof config_entries / sizeof *config_entries);
 }
 
 __attribute__((destructor)) static void client_config_deinit()
 {
-       config_free(config_entries, NUM_CONFIG_ENTRIES);
+       config_free(config_entries, sizeof config_entries / sizeof *config_entries);
 }
index fea57d26091f5951107e1f76ad9399abe81cbd3e..05fbbe70bf2c0b56791a346e73ea03c705fe8902 100644 (file)
@@ -9,6 +9,7 @@ extern struct ClientConfig {
        double view_distance;
        bool vsync;
        unsigned int meshgen_threads;
+       bool swap_mouse_buttons;
 } client_config;
 
 #endif
index b8598f70c5184fc5f493e2737e4f7d4bbb6df30b..a48e3a7df528ec3c911a0dcd988367251c2a1587 100644 (file)
@@ -77,7 +77,7 @@ static void wield_update(ModelNode *hand, ModelNode *arm, ItemType item)
 
        if (arm) {
                arm->rot.x = mesh ? -M_PI / 8.0 : 0.0;
-               model_node_transform(arm);              
+               model_node_transform(arm);
        }
 }
 
@@ -85,6 +85,8 @@ void client_inventory_init_player(ClientEntity *entity)
 {
        ClientPlayerData *data = entity->extra;
 
+       pthread_mutex_init(&data->mtx_inv, NULL);
+
        item_stack_initialize(&data->inventory.left);
        item_stack_initialize(&data->inventory.right);
 
@@ -96,6 +98,8 @@ void client_inventory_deinit_player(ClientEntity *entity)
 {
        ClientPlayerData *data = entity->extra;
 
+       pthread_mutex_destroy(&data->mtx_inv);
+
        item_stack_destroy(&data->inventory.left);
        item_stack_destroy(&data->inventory.right);
 }
@@ -107,6 +111,7 @@ void client_inventory_update_player(__attribute__((unused)) void *peer, ToClient
                return;
 
        ClientPlayerData *data = entity->extra;
+       pthread_mutex_lock(&data->mtx_inv);
 
        item_stack_deserialize(&data->inventory.left, &pkt->left);
        item_stack_deserialize(&data->inventory.right, &pkt->right);
@@ -114,5 +119,6 @@ void client_inventory_update_player(__attribute__((unused)) void *peer, ToClient
        wield_update(data->bones.hand_left,  data->bones.arm_left,  data->inventory.left.type);
        wield_update(data->bones.hand_right, data->bones.arm_right, data->inventory.right.type);
 
+       pthread_mutex_unlock(&data->mtx_inv);
        refcount_drp(&entity->rc);
 }
index 923fd74c8c0477a05015f4a8669e1e44ecf6d979..3e6d47b4cb0cc513d5ff5accc9456cf9dd0ce4c1 100644 (file)
@@ -1,25 +1,37 @@
 #include "client/client_item.h"
+#include "client/interact.h"
+#include "node.h"
+
+static bool use_dig(__attribute__((unused)) ItemStack *stack)
+{
+       return interact_pointed.exists
+               && (node_defs[interact_pointed.node].dig_class & item_defs[stack->type].dig_class);
+}
 
 ClientItemDef client_item_defs[COUNT_ITEM] = {
        // unknown
        {
                .mesh_path = RESSOURCE_PATH "meshes/unknown.txt",
                .mesh = {0},
+               .use = NULL,
        },
        // none
        {
                .mesh_path = NULL,
                .mesh = {0},
+               .use = NULL,
        },
        // pickaxe
        {
                .mesh_path = RESSOURCE_PATH "meshes/pickaxe.txt",
                .mesh = {0},
+               .use = &use_dig,
        },
        // axe
        {
                .mesh_path = RESSOURCE_PATH "meshes/axe.txt",
                .mesh = {0},
+               .use = &use_dig,
        },
 };
 
index 0105abfba0838bc7afd83fc1b2486b5a945708a9..bffb251585baa0c72fc22ebb9d34c53895a46af4 100644 (file)
@@ -1,12 +1,15 @@
 #ifndef _CLIENT_ITEM_H_
 #define _CLIENT_ITEM_H_
 
+#include <stdbool.h>
 #include "client/mesh.h"
 #include "item.h"
+#include "node.h"
 
 typedef struct {
        const char *mesh_path;
        Mesh mesh;
+       bool (*use)(ItemStack *stack);
 } ClientItemDef;
 
 extern ClientItemDef client_item_defs[];
index 9ab340c6519d30198c86d7b53285f5acdbc8fbcf..a92b4c1dba65cfafe6a60b760662e4f54721cdd3 100644 (file)
@@ -248,7 +248,7 @@ ClientEntity *client_player_entity(u64 id)
 {
        ClientEntity *entity = client_entity_grab(id);
 
-       if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER] 
+       if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER]
                        || entity->type == &client_entity_types[ENTITY_PLAYER])
                return entity;
 
index 1028955f97af29e6145bdc449740f3d12467cd82..61310833847f12e0f3e1487a9205a26d5b72bad2 100644 (file)
@@ -16,6 +16,7 @@ typedef struct {
                ItemStack left;
                ItemStack right;
        } inventory;
+       pthread_mutex_t mtx_inv;
        struct ClientPlayerBones {
                ModelNode *nametag;
                ModelNode *neck;
index 148c0844f656b1495f5fdf11ce6eb26db8cc735a..9a3e52f78545a2171cfde8a61d528fd5769ffbb0 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <pthread.h>
 #include "client/client.h"
+#include "client/facedir.h"
 #include "client/facecache.h"
 #include "client/client_config.h"
 #include "client/client_player.h"
@@ -170,6 +171,9 @@ static void on_create_chunk(TerrainChunk *chunk)
        meta->sync = 0;
        meta->model = NULL;
        meta->empty = false;
+       meta->has_model = false;
+       for (int i = 0; i < 6; i++)
+               meta->depends[i] = false;
 }
 
 // callback for deleting a chunk
@@ -258,47 +262,49 @@ u32 client_terrain_get_load_distance()
 void client_terrain_chunk_received(TerrainChunk *chunk)
 {
        pthread_mutex_lock(&chunk->mtx);
-       TerrainChunkMeta *extra = chunk->extra;
-       if (extra->state == CHUNK_RECIEVING)
-               extra->state = CHUNK_FRESH;
+       TerrainChunkMeta *meta = chunk->extra;
+
+       if (meta->state == CHUNK_RECIEVING)
+               meta->state = CHUNK_FRESH;
+
        pthread_mutex_unlock(&chunk->mtx);
 
-       client_terrain_meshgen_task(chunk);
+       client_terrain_meshgen_task(chunk, true);
 
-       v3s32 neighbors[6] = {
-               {+1,  0,  0},
-               { 0, +1,  0},
-               { 0,  0, +1},
-               {-1,  0,  0},
-               { 0, -1,  0},
-               { 0,  0, -1},
-       };
+       for (int i = 0; i < 6; i++) {
+               TerrainChunk *neighbor = terrain_get_chunk(client_terrain,
+                       v3s32_sub(chunk->pos, facedir[i]), false);
+               if (!neighbor)
+                       continue;
 
-       for (int i = 0; i < 6; i++)
-               client_terrain_meshgen_task(terrain_get_chunk(client_terrain,
-                       v3s32_add(chunk->pos, neighbors[i]), false));
+               pthread_mutex_lock(&neighbor->mtx);
+               TerrainChunkMeta *neighbor_meta = neighbor->extra;
+               if (neighbor_meta->depends[i])
+                       client_terrain_meshgen_task(neighbor, true);
+               pthread_mutex_unlock(&neighbor->mtx);
+       }
 }
 
 // enqueue chunk to mesh update queue
-void client_terrain_meshgen_task(TerrainChunk *chunk)
+void client_terrain_meshgen_task(TerrainChunk *chunk, bool changed)
 {
-       if (!chunk)
+       TerrainChunkMeta *meta = chunk->extra;
+       if (meta->queue)
                return;
 
-       pthread_mutex_lock(&chunk->mtx);
+       if (meta->empty) {
+               meta->has_model = true;
 
-       TerrainChunkMeta *meta = chunk->extra;
-       if (!meta->queue) {
-               if (meta->empty) {
-                       if (meta->model) {
-                               meta->model->flags.delete = 1;
-                               meta->model = NULL;
-                       }
-               } else {
-                       meta->queue = true;
-                       queue_enq(&meshgen_tasks, chunk);
+               if (meta->model) {
+                       meta->model->flags.delete = 1;
+                       meta->model = NULL;
                }
-       }
+       } else {
+               meta->queue = true;
 
-       pthread_mutex_unlock(&chunk->mtx);
+               if (meta->has_model && changed)
+                       queue_ppd(&meshgen_tasks, chunk);
+               else
+                       queue_enq(&meshgen_tasks, chunk);
+       }
 }
index f1e1355f9d7b28baaf9c6d780422b8fac7441fbc..fc1c8204e048b5c343cce689f54db5d2e4fb78a2 100644 (file)
@@ -18,17 +18,19 @@ typedef struct {
        u64 sync;                // keep track of when a chunk was synced the last time (used to detect when a chunk got out of and then back into load distance)
        Model *model;            // generated by terrain_gfx
        bool empty;              // whether the chunk is all air
+       bool has_model;          // whether the chunk got a model before
+       bool depends[6];         // neighbours it depends on
 } TerrainChunkMeta;
 
 extern Terrain *client_terrain;
 
-void client_terrain_init();                              // called on startup
-void client_terrain_deinit();                            // called on shutdown
-void client_terrain_set_load_distance(u32 dist);         // update load distance
-u32 client_terrain_get_load_distance();                  // return load distance
-void client_terrain_start();                             // start meshgen and sync threads
-void client_terrain_stop();                              // stop meshgen and sync threads
-void client_terrain_chunk_received(TerrainChunk *chunk); // called when a chunk was recieved from server
-void client_terrain_meshgen_task(TerrainChunk *chunk);   // enqueue chunk to mesh update queue
+void client_terrain_init();                                          // called on startup
+void client_terrain_deinit();                                        // called on shutdown
+void client_terrain_set_load_distance(u32 dist);                     // update load distance
+u32 client_terrain_get_load_distance();                              // return load distance
+void client_terrain_start();                                         // start meshgen and sync threads
+void client_terrain_stop();                                          // stop meshgen and sync threads
+void client_terrain_chunk_received(TerrainChunk *chunk);             // called when a chunk was recieved from server
+void client_terrain_meshgen_task(TerrainChunk *chunk, bool changed); // enqueue chunk to mesh update queue
 
 #endif
diff --git a/src/client/facedir.c b/src/client/facedir.c
new file mode 100644 (file)
index 0000000..4eaf32c
--- /dev/null
@@ -0,0 +1,10 @@
+#include "client/facedir.h"
+
+v3s32 facedir[6] = {
+       {+0, +0, -1},
+       {+0, +0, +1},
+       {-1, +0, +0},
+       {+1, +0, +0},
+       {+0, -1, +0},
+       {+0, +1, +0},
+};
diff --git a/src/client/facedir.h b/src/client/facedir.h
new file mode 100644 (file)
index 0000000..b676f0e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _FACEDIR_H_
+#define _FACEDIR_H_
+
+#include "types.h"
+
+extern v3s32 facedir[];
+
+#endif // _FACEDIR_H_
index 00ede8a173ebe62e6443112f08e64a0308387a19..32c181b24b1e8726c4c5b5b78694547c489175f0 100644 (file)
@@ -4,9 +4,12 @@
 #include <stdlib.h>
 #include "client/camera.h"
 #include "client/client.h"
+#include "client/client_config.h"
+#include "client/client_inventory.h"
 #include "client/client_player.h"
 #include "client/debug_menu.h"
 #include "client/gui.h"
+#include "client/interact.h"
 #include "client/input.h"
 #include "client/screenshot.h"
 #include "client/window.h"
@@ -218,3 +221,11 @@ void input_cursor(double current_x, double current_y)
        pthread_rwlock_unlock(&entity->lock_pos_rot);
        refcount_drp(&entity->rc);
 }
+
+void input_click(bool left)
+{
+       if (client_config.swap_mouse_buttons)
+               left = !left;
+
+       interact_use(left);
+}
index 9d63151ca567c832a1b77aed9032066ebffd8881..96c79444a475c698139739f15b4b148df2270473 100644 (file)
@@ -1,10 +1,12 @@
 #ifndef _INPUT_H_
 #define _INPUT_H_
 
+#include <stdbool.h>
 #include "types.h"
 
 void input_init();
 void input_tick(f64 dtime);
 void input_cursor(double current_x, double current_y);
+void input_click(bool left);
 
 #endif // _INPUT_H_
index a4c22514dc5183fbd27c0566ed6a6cb767ebc4f3..9aba87b07c5515281cb0657b84318fc0f72b0080 100644 (file)
@@ -1,7 +1,10 @@
 #include <linmath.h/linmath.h>
 #include <stdio.h>
 #include "client/camera.h"
+#include "client/client.h"
+#include "client/client_item.h"
 #include "client/client_node.h"
+#include "client/client_player.h"
 #include "client/cube.h"
 #include "client/debug_menu.h"
 #include "client/frustum.h"
@@ -84,9 +87,9 @@ void interact_tick()
        bool old_exists = interact_pointed.exists;
        v3s32 old_pointed = interact_pointed.pos;
        if ((interact_pointed.exists = raycast(
-                               (v3f64) {camera.eye  [0], camera.eye  [1], camera.eye  [2]}, 
+                               (v3f64) {camera.eye  [0], camera.eye  [1], camera.eye  [2]},
                                (v3f64) {camera.front[0], camera.front[1], camera.front[2]},
-                               5, &interact_pointed.pos, &interact_pointed.node)) 
+                               5, &interact_pointed.pos, &interact_pointed.node))
                        && !v3s32_equals(interact_pointed.pos, old_pointed)) {
                mat4x4_translate(model,
                        interact_pointed.pos.x, interact_pointed.pos.y, interact_pointed.pos.z);
@@ -96,7 +99,7 @@ void interact_tick()
        }
 
        if (old_exists && !interact_pointed.exists)
-               debug_menu_changed(ENTRY_POINTED);      
+               debug_menu_changed(ENTRY_POINTED);
 }
 
 void interact_render()
@@ -111,3 +114,24 @@ void interact_render()
        glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, mvp[0]); GL_DEBUG
        mesh_render(&selection_mesh);
 }
+
+void interact_use(bool left)
+{
+       ClientEntity *entity = client_player_entity_local();
+       if (!entity)
+               return;
+
+       ClientPlayerData *data = entity->extra;
+       pthread_mutex_lock(&data->mtx_inv);
+
+       ItemStack *stack = left ? &data->inventory.left : &data->inventory.right;
+       if (client_item_defs[stack->type].use && client_item_defs[stack->type].use(stack))
+               dragonnet_peer_send_ToServerInteract(client, &(ToServerInteract) {
+                       .left = left,
+                       .pointed = interact_pointed.exists,
+                       .pos = interact_pointed.pos,
+               });
+
+       pthread_mutex_unlock(&data->mtx_inv);
+       refcount_drp(&entity->rc);
+}
index aa3389dbd1411e5b0a860b6de3f257e03455f43b..c39e8baeed26738c18e585406655bbaff8a83a74 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _INTERACT_H_
 #define _INTERACT_H_
 
+#include <stdbool.h>
+#include "node.h"
+#include "types.h"
+
 extern struct InteractPointed {
        bool exists;
        v3s32 pos;
@@ -11,5 +15,6 @@ bool interact_init();
 void interact_deinit();
 void interact_tick();
 void interact_render();
+void interact_use(bool left);
 
 #endif // _INTERACT_H_
index 52877d9ae54b493ca5ee6176b4a6561d7656b2b0..32380e423f892f280dbbb3ef7ce27dd77074f61a 100644 (file)
@@ -6,6 +6,7 @@
 #include "client/client_node.h"
 #include "client/client_terrain.h"
 #include "client/cube.h"
+#include "client/facedir.h"
 #include "client/frustum.h"
 #include "client/gl_debug.h"
 #include "client/light.h"
@@ -20,8 +21,9 @@ typedef struct {
        TerrainChunk *chunk;
        v3s32 chunkp;
        TerrainChunk *nbrs[6];
-       bool tried_nbrs[6];
-       bool cull_edges;
+       bool *tried_nbrs;
+       bool show_edges;
+       bool shown_edges;
 } ChunkRenderData;
 
 static VertexLayout terrain_vertex_layout = {
@@ -36,15 +38,6 @@ static VertexLayout terrain_vertex_layout = {
        .size = sizeof(TerrainVertex),
 };
 
-static v3s32 face_dir[6] = {
-       {+0, +0, -1},
-       {+0, +0, +1},
-       {-1, +0, +0},
-       {+1, +0, +0},
-       {+0, -1, +0},
-       {+0, +1, +0},
-};
-
 static v3f32 center_offset = {
        CHUNK_SIZE * 0.5f + 0.5f,
        CHUNK_SIZE * 0.5f + 0.5f,
@@ -57,19 +50,17 @@ static GLint loc_VP;
 static LightShader light_shader;
 static ModelShader model_shader;
 
-static inline bool cull_face(NodeType self, NodeType nbr)
+static inline bool show_face(NodeType self, NodeType nbr)
 {
        switch (client_node_defs[self].visibility) {
                case VISIBILITY_CLIP:
-                       return false;
+                       return true;
 
                case VISIBILITY_BLEND:
-                       return nbr == NODE_UNLOADED
-                               || nbr == self;
+                       return nbr != self;
 
                case VISIBILITY_SOLID:
-                       return nbr == NODE_UNLOADED
-                               || client_node_defs[nbr].visibility == VISIBILITY_SOLID;
+                       return nbr != NODE_UNLOADED && client_node_defs[nbr].visibility != VISIBILITY_SOLID;
 
                default: // impossible
                        break;
@@ -94,7 +85,7 @@ static inline void render_node(ChunkRenderData *data, v3s32 offset)
                args.pos = v3s32_add(offset, data->chunkp);
 
        for (args.f = 0; args.f < 6; args.f++) {
-               v3s32 nbr_offset = v3s32_add(offset, face_dir[args.f]);
+               v3s32 nbr_offset = v3s32_add(offset, facedir[args.f]);
 
                TerrainChunk *nbr_chunk;
 
@@ -104,7 +95,7 @@ static inline void render_node(ChunkRenderData *data, v3s32 offset)
                        nbr_chunk = data->chunk;
                } else if (!(nbr_chunk = data->nbrs[args.f]) && !data->tried_nbrs[args.f]) {
                        nbr_chunk = data->nbrs[args.f] = terrain_get_chunk(client_terrain,
-                               v3s32_add(data->chunk->pos, face_dir[args.f]), false);
+                               v3s32_add(data->chunk->pos, facedir[args.f]), false);
                        data->tried_nbrs[args.f] = true;
                }
 
@@ -115,13 +106,15 @@ static inline void render_node(ChunkRenderData *data, v3s32 offset)
                                [(nbr_offset.y + CHUNK_SIZE) % CHUNK_SIZE]
                                [(nbr_offset.z + CHUNK_SIZE) % CHUNK_SIZE].type;
 
-               if (cull_face(args.node->type, nbr_node)) {
-                       // exception to culling rules: don't cull solid edge nodes, unless cull_edges
-                       if (data->cull_edges || nbr_chunk == data->chunk || def->visibility != VISIBILITY_SOLID)
-                               continue;
-               } else {
+               bool show = show_face(args.node->type, nbr_node);
+
+               if (show)
                        data->visible = true;
-               }
+               else if (data->show_edges && nbr_chunk != data->chunk && def->visibility == VISIBILITY_SOLID)
+                       data->shown_edges = show = true;
+
+               if (!show)
+                       continue;
 
                ModelBatch *batch = data->batch;
 
@@ -145,19 +138,30 @@ static inline void render_node(ChunkRenderData *data, v3s32 offset)
 
 static void animate_chunk_model(Model *model, f64 dtime)
 {
-       if ((model->root->scale.x += dtime * 2.0f) > 1.0f) {
+       bool finished = (model->root->scale.x += dtime * 2.0f) > 1.0f;
+       if (finished)
                model->root->scale.x = 1.0f;
-               client_terrain_meshgen_task(model->extra);
-       }
 
        model->root->scale.z
                = model->root->scale.y
                = model->root->scale.x;
 
        model_node_transform(model->root);
+
+       if (finished) {
+               model->callbacks.step = NULL;
+
+               if (model->extra) {
+                       TerrainChunk *chunk = model->extra;
+
+                       pthread_mutex_lock(&chunk->mtx);
+                       client_terrain_meshgen_task(chunk, false);
+                       pthread_mutex_unlock(&chunk->mtx);
+               }
+       }
 }
 
-static Model *create_chunk_model(TerrainChunk *chunk, bool animate)
+static Model *create_chunk_model(TerrainChunk *chunk, bool animate, bool *depends)
 {
        ChunkRenderData data = {
                .visible = false,
@@ -167,21 +171,23 @@ static Model *create_chunk_model(TerrainChunk *chunk, bool animate)
                .chunk = chunk,
                .chunkp = v3s32_scale(chunk->pos, CHUNK_SIZE),
                .nbrs = {NULL},
-               .tried_nbrs = {false},
-               .cull_edges = !animate,
+               .tried_nbrs = depends,
+               .show_edges = animate,
+               .shown_edges = false,
        };
 
        CHUNK_ITERATE
                render_node(&data, (v3s32) {x, y, z});
 
-       if (!data.batch->textures.siz && !data.batch_transparent->textures.siz) {
+       if (!data.visible || (!data.batch->textures.siz && !data.batch_transparent->textures.siz)) {
                model_batch_free(data.batch);
                model_batch_free(data.batch_transparent);
                return NULL;
        }
 
        Model *model = model_create();
-       model->extra = chunk;
+       if (data.shown_edges)
+               model->extra = chunk;
        model->box = (aabb3f32) {
                v3f32_sub((v3f32) {-1.0f, -1.0f, -1.0f}, center_offset),
                v3f32_add((v3f32) {+1.0f, +1.0f, +1.0f}, center_offset)};
@@ -202,6 +208,10 @@ static Model *create_chunk_model(TerrainChunk *chunk, bool animate)
                model_batch_free(data.batch_transparent);
        }
 
+       for (int i = 0; i < 6; i++)
+               if (data.nbrs[i])
+                       data.tried_nbrs[i] = true;
+
        return model;
 }
 
@@ -256,15 +266,18 @@ void terrain_gfx_update()
 void terrain_gfx_make_chunk_model(TerrainChunk *chunk)
 {
        TerrainChunkMeta *meta = chunk->extra;
+       pthread_mutex_lock(&chunk->mtx);
 
-       bool animate = true;
+       bool animate;
+       if (meta->model)
+               animate = meta->model->callbacks.step ? true : false;
+       else
+               animate = !meta->has_model;
 
-       pthread_mutex_lock(&chunk->mtx);
-       if (meta->model && meta->model->root->scale.x == 1.0f)
-               animate = false;
        pthread_mutex_unlock(&chunk->mtx);
 
-       Model *model = create_chunk_model(chunk, animate);
+       bool depends[6] = {false};
+       Model *model = create_chunk_model(chunk, animate, depends);
 
        pthread_mutex_lock(&chunk->mtx);
 
@@ -282,5 +295,10 @@ void terrain_gfx_make_chunk_model(TerrainChunk *chunk)
        }
 
        meta->model = model;
+       meta->has_model = true;
+
+       for (int i = 0; i < 6; i++)
+               meta->depends[i] = depends[i];
+
        pthread_mutex_unlock(&chunk->mtx);
 }
index b9460eb14ac3676f4211efe19dcd89fac0fb68a6..f1b65b5d8cc271dda53127e5f317242e4a541df4 100644 (file)
@@ -49,6 +49,12 @@ static void window_pos_callback(__attribute__((unused)) GLFWwindow *handle, int
        }
 }
 
+static void mouse_button_callback(__attribute__((unused)) GLFWwindow *handle, int button, int action, __attribute__((unused)) int mods)
+{
+       if ((button == GLFW_MOUSE_BUTTON_RIGHT || button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS)
+               input_click(button == GLFW_MOUSE_BUTTON_LEFT);
+}
+
 void window_enter_fullscreen()
 {
        window.fullscreen = true;
@@ -108,6 +114,7 @@ bool window_init()
        glfwSetFramebufferSizeCallback(window.handle, &framebuffer_size_callback);
        glfwSetCursorPosCallback(window.handle, &cursor_pos_callback);
        glfwSetWindowPosCallback(window.handle, &window_pos_callback);
+       glfwSetMouseButtonCallback(window.handle, &mouse_button_callback);
 
        return true;
 }
diff --git a/src/dig.h b/src/dig.h
new file mode 100644 (file)
index 0000000..d12d63e
--- /dev/null
+++ b/src/dig.h
@@ -0,0 +1,11 @@
+#ifndef _DIG_H_
+#define _DIG_H_
+
+typedef enum {
+       DIG_NONE = 0x0,
+       DIG_STONE = 0x01,
+       DIG_WOOD = 0x02,
+       DIG_DIRT = 0x04,
+} DigClass;
+
+#endif // _DIG_H_
index 25a1a2cc172817c641db3a15dc882f363ff80ba7..51beaf8ac2d3e7fd46df3521cf8273c9cb8d0dd4 100644 (file)
@@ -7,14 +7,14 @@ void item_stack_initialize(ItemStack *stack)
        stack->count = 1;
        stack->data = NULL;
 
-       if (item_defs[stack->type].create)
-               item_defs[stack->type].create(stack);   
+       if (item_defs[stack->type].callbacks.create)
+               item_defs[stack->type].callbacks.create(stack);
 }
 
 void item_stack_destroy(ItemStack *stack)
 {
-       if (item_defs[stack->type].delete)
-               item_defs[stack->type].delete(stack);   
+       if (item_defs[stack->type].callbacks.delete)
+               item_defs[stack->type].callbacks.delete(stack);
 
        if (stack->data) {
                free(stack->data);
@@ -31,11 +31,11 @@ void item_stack_set(ItemStack *stack, ItemType type, u32 count, Blob buffer)
        stack->data = item_defs[stack->type].data_size > 0 ?
                malloc(item_defs[stack->type].data_size) : NULL;
 
-       if (item_defs[stack->type].create)
-               item_defs[stack->type].create(stack);
+       if (item_defs[stack->type].callbacks.create)
+               item_defs[stack->type].callbacks.create(stack);
 
-       if (item_defs[stack->type].deserialize)
-               item_defs[stack->type].deserialize(&buffer, stack->data);
+       if (item_defs[stack->type].callbacks.deserialize)
+               item_defs[stack->type].callbacks.deserialize(&buffer, stack->data);
 }
 
 void item_stack_serialize(ItemStack *stack, SerializedItemStack *serialized)
@@ -44,8 +44,8 @@ void item_stack_serialize(ItemStack *stack, SerializedItemStack *serialized)
        serialized->count = stack->count;
        serialized->data = (Blob) {0, NULL};
 
-       if (item_defs[stack->type].serialize)
-               item_defs[stack->type].serialize(&serialized->data, stack->data);
+       if (item_defs[stack->type].callbacks.serialize)
+               item_defs[stack->type].callbacks.serialize(&serialized->data, stack->data);
 }
 
 void item_stack_deserialize(ItemStack *stack, SerializedItemStack *serialized)
@@ -54,7 +54,7 @@ void item_stack_deserialize(ItemStack *stack, SerializedItemStack *serialized)
 
        if (type >= COUNT_ITEM)
                type = ITEM_UNKNOWN;
-       
+
        item_stack_set(stack, type, serialized->count, serialized->data);
 }
 
@@ -63,36 +63,28 @@ ItemDef item_defs[COUNT_ITEM] = {
        {
                .stackable = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // none
        {
                .stackable = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // pickaxe
        {
                .stackable = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_STONE,
+               .callbacks = {NULL},
        },
        // axe
        {
                .stackable = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_WOOD,
+               .callbacks = {NULL},
        },
 };
index accf3abd49dd2c855ac848fdd9afba3de8487d03..6d5fd3c51b78f5654837f397cc7345d1fcc8dfa3 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
+#include "dig.h"
 #include "types.h"
 
 typedef enum {
@@ -22,10 +23,13 @@ typedef struct {
 typedef struct {
        bool stackable;
        size_t data_size;
-       void (*create)(ItemStack *stack);
-       void (*delete)(ItemStack *stack);
-       void (*serialize)(Blob *buffer, void *data);
-       void (*deserialize)(Blob *buffer, void *data);
+       DigClass dig_class;
+       struct {
+               void (*create)(ItemStack *stack);
+               void (*delete)(ItemStack *stack);
+               void (*serialize)(Blob *buffer, void *data);
+               void (*deserialize)(Blob *buffer, void *data);
+       } callbacks;
 } ItemDef;
 
 void item_stack_initialize(ItemStack *stack);
index c9c2c1cf205e6d9b66a469de49ba5b3e93b903fd..2786aec15f52033a8415ef8c404465ff5ab5e159 100644 (file)
@@ -1,3 +1,4 @@
+#include "dig.h"
 #include "node.h"
 #include "terrain.h"
 #include "types.h"
@@ -7,144 +8,142 @@ NodeDef node_defs[NODE_UNLOADED] = {
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // air
        {
                .solid = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // grass
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_DIRT,
+               .callbacks = {NULL},
        },
        // dirt
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_DIRT,
+               .callbacks = {NULL},
        },
        // stone
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_STONE,
+               .callbacks = {NULL},
        },
        // snow
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_DIRT,
+               .callbacks = {NULL},
        },
        // oak wood
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_WOOD,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // oak leaves
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_NONE,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // pine wood
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_WOOD,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // pine leaves
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_NONE,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // palm wood
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_WOOD,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // palm leaves
        {
                .solid = true,
                .data_size = sizeof(ColorData),
-               .create = NULL,
-               .delete = NULL,
-               .serialize = (void *) &ColorData_write,
-               .deserialize = (void *) &ColorData_read,
+               .dig_class = DIG_NONE,
+               .callbacks = {
+                       .create = NULL,
+                       .delete = NULL,
+                       .serialize = (void *) &ColorData_write,
+                       .deserialize = (void *) &ColorData_read,
+               },
        },
        // sand
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_DIRT,
+               .callbacks = {NULL},
        },
        // water
        {
                .solid = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // lava
        {
                .solid = false,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_NONE,
+               .callbacks = {NULL},
        },
        // vulcanostone
        {
                .solid = true,
                .data_size = 0,
-               .create = NULL,
-               .delete = NULL,
-               .serialize = NULL,
-               .deserialize = NULL,
+               .dig_class = DIG_STONE,
+               .callbacks = {NULL},
        },
 };
index b660d179fe0ba4a5d3cd6378ebc1edf668cde50f..3c622e2d579668c206841ca780112e43d89b0cd6 100644 (file)
@@ -30,10 +30,13 @@ struct TerrainNode;
 typedef struct {
        bool solid;
        size_t data_size;
-       void (*create)(struct TerrainNode *node);
-       void (*delete)(struct TerrainNode *node);
-       void (*serialize)(Blob *buffer, void *data);
-       void (*deserialize)(Blob *buffer, void *data);
+       unsigned long dig_class;
+       struct {
+               void (*create)(struct TerrainNode *node);
+               void (*delete)(struct TerrainNode *node);
+               void (*serialize)(Blob *buffer, void *data);
+               void (*deserialize)(Blob *buffer, void *data);
+       } callbacks;
 } NodeDef;
 
 extern NodeDef node_defs[];
index 114f6540489d2b022de508c5973584c20eb05d6c..0bd12059ae368dd1a438259b21afe16518f0a171 100644 (file)
@@ -7,6 +7,7 @@
 #include "interrupt.h"
 #include "server/database.h"
 #include "server/server.h"
+#include "server/server_item.h"
 #include "server/server_player.h"
 #include "server/server_terrain.h"
 
@@ -24,12 +25,16 @@ static void on_ToServerAuth(DragonnetPeer *peer, ToServerAuth *pkt)
                pkt->name = NULL;
 }
 
-// set a node on the map
-static void on_ToServerSetnode(__attribute__((unused)) DragonnetPeer *peer, ToServerSetnode *pkt)
+static void on_ToServerInteract(DragonnetPeer *peer, ToServerInteract *pkt)
 {
-       terrain_set_node(server_terrain, pkt->pos,
-               terrain_node_create(pkt->node, (Blob) {0, NULL}),
-               false, NULL);
+       ServerPlayer *player = peer->extra;
+       pthread_mutex_lock(&player->mtx_inv);
+
+       ItemStack *stack = pkt->left ? &player->inventory.left : &player->inventory.right;
+       if (server_item_defs[stack->type].use)
+               server_item_defs[stack->type].use(player, stack, pkt->pointed, pkt->pos);
+
+       pthread_mutex_unlock(&player->mtx_inv);
 }
 
 // update player's position
@@ -67,7 +72,7 @@ int main(int argc, char **argv)
        server->on_disconnect = &server_player_remove;
        server->on_recv = &on_recv;
        server->on_recv_type[DRAGONNET_TYPE_ToServerAuth        ] = (void *) &on_ToServerAuth;
-       server->on_recv_type[DRAGONNET_TYPE_ToServerSetnode     ] = (void *) &on_ToServerSetnode;
+       server->on_recv_type[DRAGONNET_TYPE_ToServerInteract    ] = (void *) &on_ToServerInteract;
        server->on_recv_type[DRAGONNET_TYPE_ToServerPosRot      ] = (void *) &on_ToServerPosRot;
        server->on_recv_type[DRAGONNET_TYPE_ToServerRequestChunk] = (void *) &on_ToServerRequestChunk;
 
index 51a39c28e209ce44d6bfd263bd1bab7dc0b7b681..242a10081f707b1170f9278e4c61f79e8ed6035b 100644 (file)
@@ -12,8 +12,7 @@ struct ServerConfig server_config = {
        }
 };
 
-#define NUM_CONFIG_ENTRIES 6
-static ConfigEntry config_entries[NUM_CONFIG_ENTRIES] = {
+static ConfigEntry config_entries[] = {
        {
                .type = CONFIG_UINT,
                .key = "load_distance",
@@ -48,10 +47,10 @@ static ConfigEntry config_entries[NUM_CONFIG_ENTRIES] = {
 
 __attribute__((constructor)) static void server_config_init()
 {
-       config_read("server.conf", config_entries, NUM_CONFIG_ENTRIES);
+       config_read("server.conf", config_entries, sizeof config_entries / sizeof *config_entries);
 }
 
 __attribute__((destructor)) static void server_config_deinit()
 {
-       config_free(config_entries, NUM_CONFIG_ENTRIES);
+       config_free(config_entries, sizeof config_entries / sizeof *config_entries);
 }
diff --git a/src/server/server_item.c b/src/server/server_item.c
new file mode 100644 (file)
index 0000000..2640695
--- /dev/null
@@ -0,0 +1,40 @@
+#include "node.h"
+#include "server/server_item.h"
+#include "server/server_terrain.h"
+
+static void use_dig(__attribute__((unused)) ServerPlayer *player, ItemStack *stack, bool pointed, v3s32 pos)
+{
+       if (!pointed)
+               return;
+
+       NodeType node = terrain_get_node(server_terrain, pos).type;
+
+       if (node == NODE_UNLOADED)
+               return;
+
+       if (!(node_defs[node].dig_class & item_defs[stack->type].dig_class))
+               return;
+
+       terrain_set_node(server_terrain, pos,
+               terrain_node_create(NODE_AIR, (Blob) {0, NULL}),
+               false, NULL);
+}
+
+ServerItemDef server_item_defs[COUNT_ITEM] = {
+       // unknown
+       {
+               .use = NULL,
+       },
+       // none
+       {
+               .use = NULL,
+       },
+       // pickaxe
+       {
+               .use = &use_dig,
+       },
+       // axe
+       {
+               .use = &use_dig,
+       },
+};
diff --git a/src/server/server_item.h b/src/server/server_item.h
new file mode 100644 (file)
index 0000000..1c6cfef
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _SERVER_ITEM_H_
+#define _SERVER_ITEM_H_
+
+#include <stdbool.h>
+#include "item.h"
+#include "server/server_player.h"
+#include "types.h"
+
+typedef struct {
+       void (*use)(ServerPlayer *player, ItemStack *stack, bool pointed, v3s32 pos);
+} ServerItemDef;
+
+extern ServerItemDef server_item_defs[];
+
+#endif // _SERVER_ITEM_H_
index 4a41d5e52a7c244a9b4f038390787d8c7a0a6a3e..c412f04ec1ee48f672c1071f19727b846ef6b59d 100644 (file)
@@ -65,10 +65,10 @@ static void send_player_inventory(ServerPlayer *client, ServerPlayer *player)
 static void send_player_inventory_existing(ServerPlayer *player, ServerPlayer *client)
 {
        if (client != player) {
-               pthread_rwlock_rdlock(&player->lock_inv);
+               pthread_mutex_lock(&player->mtx_inv);
                send_player_inventory(client, player);
-               pthread_rwlock_unlock(&player->lock_inv);
-       }       
+               pthread_mutex_unlock(&player->mtx_inv);
+       }
 }
 
 // main thread
@@ -101,7 +101,7 @@ static void player_delete(ServerPlayer *player)
 
        item_stack_destroy(&player->inventory.left);
        item_stack_destroy(&player->inventory.right);
-       pthread_rwlock_destroy(&player->lock_inv);
+       pthread_mutex_destroy(&player->mtx_inv);
 
        free(player);
 }
@@ -200,7 +200,7 @@ void server_player_add(DragonnetPeer *peer)
 
        item_stack_initialize(&player->inventory.left);
        item_stack_initialize(&player->inventory.right);
-       pthread_rwlock_init(&player->lock_inv, NULL);
+       pthread_mutex_init(&player->mtx_inv, NULL);
 
        printf("[access] connected %s\n", player->name);
        peer->extra = refcount_grb(&player->rc);
@@ -317,6 +317,11 @@ void server_player_iterate(void *func, void *arg)
        map_trv(&players_named, func, arg, &refcount_obj, TRAVERSION_INORDER);
 }
 
+void server_player_inventory_changed(ServerPlayer *player)
+{
+       server_player_iterate(&send_player_inventory, player);
+}
+
 /*
 229779
 373875
index 34af22521a17144900d6aef89f56d3228f282a74..afd7119679066d13177f1ba001836be15e74ca6a 100644 (file)
@@ -27,7 +27,7 @@ typedef struct {
                ItemStack left;
                ItemStack right;
        } inventory;
-       pthread_rwlock_t lock_inv;
+       pthread_mutex_t mtx_inv;
 } ServerPlayer;
 
 void server_player_init();
@@ -43,5 +43,6 @@ bool server_player_auth(ServerPlayer *player, char *name);
 void server_player_disconnect(ServerPlayer *player);
 void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot);
 void server_player_iterate(void *func, void *arg);
+void server_player_inventory_changed(ServerPlayer *player);
 
 #endif // _SERVER_PLAYER_H_
index b3366c8f483e4bf3b7d05299131dae7d8d86d26b..b3b3d386f4148b6d52c5101779574a11983774a3 100644 (file)
@@ -168,8 +168,8 @@ Blob terrain_serialize_chunk(TerrainChunk *chunk)
 
                NodeDef *def = &node_defs[node->type];
 
-               if (def->serialize)
-                       def->serialize(&node_data->data, node->data);
+               if (def->callbacks.serialize)
+                       def->callbacks.serialize(&node_data->data, node->data);
        }
 
        Blob buffer = {0, NULL};
@@ -248,11 +248,11 @@ TerrainNode terrain_node_create(NodeType type, Blob buffer)
        node.type = type;
        node.data = def->data_size ? malloc(def->data_size) : NULL;
 
-       if (def->create)
-               def->create(&node);
+       if (def->callbacks.create)
+               def->callbacks.create(&node);
 
-       if (def->deserialize)
-               def->deserialize(&buffer, node.data);
+       if (def->callbacks.deserialize)
+               def->callbacks.deserialize(&buffer, node.data);
 
        return node;
 }
@@ -261,8 +261,8 @@ void terrain_node_delete(TerrainNode node)
 {
        NodeDef *def = &node_defs[node.type];
 
-       if (def->delete)
-               def->delete(&node);
+       if (def->callbacks.delete)
+               def->callbacks.delete(&node);
 
        if (node.data)
                free(node.data);
index 824872649eda86dc296619e48c28f647a64d95c8..6d187239d79a3d269687f0aecb7f381e6fc8a055 100644 (file)
@@ -35,9 +35,10 @@ SerializedItemStack
 pkt ToServerAuth
        String name
 
-pkt ToServerSetnode
+pkt ToServerInteract
+       u8 left
+       u8 pointed
        v3s32 pos
-       u32 node
 
 pkt ToServerPosRot
        v3f64 pos