From 7edcc13168d2d0738225d8adb5e431a069919ccf Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 12 Feb 2022 23:17:32 +0100 Subject: [PATCH] Use dragonnet --- .gitignore | 18 ++- .gitmodules | 15 ++- deps/dragonnet | 1 + deps/dragonstd | 1 + deps/dragontype | 2 +- deps/linenoise | 1 + singleplayer.sh | 2 +- snapshot.sh | 2 +- src/CMakeLists.txt | 90 +++++++++---- src/client/camera.h | 2 +- src/client/client.c | 184 ++++++++++--------------- src/client/client.h | 25 +--- src/client/client_auth.c | 53 ++++++++ src/client/client_auth.h | 21 +++ src/client/client_commands.c | 129 ------------------ src/client/client_commands.h | 25 ---- src/client/client_map.c | 11 +- src/client/client_map.h | 2 +- src/client/client_node.c | 32 ++--- src/client/client_player.c | 8 +- src/client/client_player.h | 2 +- src/client/facecache.c | 2 +- src/client/facecache.h | 2 +- src/client/font.c | 4 +- src/client/font.h | 1 + src/client/frustum.h | 2 +- src/client/game.c | 11 +- src/client/game.h | 4 +- src/client/gui.c | 6 +- src/client/gui.h | 6 +- src/client/input.c | 2 +- src/client/input.h | 2 +- src/client/object.h | 4 +- src/client/scene.c | 2 +- src/client/scene.h | 6 +- src/client/sky.c | 12 +- src/client/texture.c | 2 +- src/day.c | 2 +- src/day.h | 2 +- src/debug.sh | 4 +- src/environment.h | 2 +- src/map.c | 94 +++++-------- src/map.h | 13 +- src/mktypes.sh | 3 + src/network.c | 55 -------- src/network.h | 27 ---- src/node.c | 43 ++---- src/node.h | 10 +- src/perlin.h | 2 +- src/server/biomes.c | 14 +- src/server/biomes.h | 2 +- src/server/database.c | 67 ++++------ src/server/mapgen.c | 7 +- src/server/server.c | 206 ++++++++-------------------- src/server/server.h | 39 +----- src/server/server_commands.c | 123 ----------------- src/server/server_commands.h | 26 ---- src/server/server_map.c | 86 ++++++------ src/server/server_map.h | 19 ++- src/server/server_player.c | 252 +++++++++++++++++++++++++++++++++++ src/server/server_player.h | 39 ++++++ src/server/trees.c | 4 +- src/server/trees.h | 4 +- src/server/voxelctx.c | 18 ++- src/server/voxelctx.h | 4 +- src/types.def | 50 +++++++ src/util.c | 143 +------------------- src/util.h | 24 ---- 68 files changed, 862 insertions(+), 1216 deletions(-) create mode 160000 deps/dragonnet create mode 160000 deps/dragonstd create mode 160000 deps/linenoise create mode 100644 src/client/client_auth.c create mode 100644 src/client/client_auth.h delete mode 100644 src/client/client_commands.c delete mode 100644 src/client/client_commands.h create mode 100755 src/mktypes.sh delete mode 100644 src/network.c delete mode 100644 src/network.h delete mode 100644 src/server/server_commands.c delete mode 100644 src/server/server_commands.h create mode 100644 src/server/server_player.c create mode 100644 src/server/server_player.h create mode 100644 src/types.def diff --git a/.gitignore b/.gitignore index 2316d5c..652ffa0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +# CMake CMakeLists.txt.user CMakeCache.txt CMakeFiles @@ -9,11 +10,20 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps -DragonblocksServer + +# Binaries Dragonblocks +DragonblocksServer +DragonblocksAlpha-*.zip + +# Data +client.conf +server.conf world.sqlite world.sqlite-journal -DragonblocksAlpha-*.zip -src/version.h screenshot-*.png -*.conf + +# Generated code +src/version.h +src/types.c +src/types.h diff --git a/.gitmodules b/.gitmodules index bb962ba..ae8eb62 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,12 +7,21 @@ [submodule "deps/stb"] path = deps/stb url = https://github.com/nothings/stb -[submodule "deps/dragontype"] - path = deps/dragontype - url = https://github.com/dragonblocks/dragontype +[submodule "deps/dragonstd"] + path = deps/dragonstd + url = https://github.com/dragonblocks/dragonstd [submodule "deps/endian.h"] path = deps/endian.h url = https://github.com/dragonblocks/endian.h [submodule "deps/dragonport"] path = deps/dragonport url = https://github.com/dragonblocks/dragonport +[submodule "deps/dragonnet"] + path = deps/dragonnet + url = https://github.com/dragonblocks/dragonnet +[submodule "deps/linenoise"] + path = deps/linenoise + url = https://github.com/antirez/linenoise +[submodule "deps/dragontype"] + path = deps/dragontype + url = https://github.com/dragonblocks/dragontype diff --git a/deps/dragonnet b/deps/dragonnet new file mode 160000 index 0000000..b2fd5e9 --- /dev/null +++ b/deps/dragonnet @@ -0,0 +1 @@ +Subproject commit b2fd5e955c0f910fdd1abf89626cfe324efbfe90 diff --git a/deps/dragonstd b/deps/dragonstd new file mode 160000 index 0000000..39b52e8 --- /dev/null +++ b/deps/dragonstd @@ -0,0 +1 @@ +Subproject commit 39b52e8cfa889d55008f2edd0933d6b421556c34 diff --git a/deps/dragontype b/deps/dragontype index b3c245b..61292ea 160000 --- a/deps/dragontype +++ b/deps/dragontype @@ -1 +1 @@ -Subproject commit b3c245ba9b111462f2fff6178b08b486cd553f1b +Subproject commit 61292ea8a973ba03f93ebf4acde705071e15ccaf diff --git a/deps/linenoise b/deps/linenoise new file mode 160000 index 0000000..97d2850 --- /dev/null +++ b/deps/linenoise @@ -0,0 +1 @@ +Subproject commit 97d2850af13c339369093b78abe5265845d78220 diff --git a/singleplayer.sh b/singleplayer.sh index 1475815..120f4a2 100755 --- a/singleplayer.sh +++ b/singleplayer.sh @@ -1,2 +1,2 @@ #! /bin/bash -./DragonblocksServer 4000 & echo "singleplayer" | ./Dragonblocks localhost 4000; killall DragonblocksServer +./DragonblocksServer "[::1]:4000" & echo "singleplayer" | ./Dragonblocks "[::1]:4000"; killall DragonblocksServer diff --git a/snapshot.sh b/snapshot.sh index 55be6de..c0a7976 100755 --- a/snapshot.sh +++ b/snapshot.sh @@ -4,7 +4,7 @@ cp -r * .build/ cd .build/ mkdir build cd build -if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release && make clean && make -j$(nproc)); then +if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="" && make clean && make -j$(nproc)); then cd ../.. rm -rf .build exit 1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3fa7299..7c96075 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,31 +1,42 @@ cmake_minimum_required(VERSION 3.12) - project(Dragonblocks) +# Variables + +set(DEPS_DIR "${CMAKE_SOURCE_DIR}/../deps/") + if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) + set(CMAKE_BUILD_TYPE Debug) endif() +if(NOT RESSOURCE_PATH) + set(RESSOURCE_PATH "../") +endif() + +# Dependencies + find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(glfw3 3.3 REQUIRED) find_package(Freetype REQUIRED) +# Options + +add_compile_definitions("RESSOURCE_PATH=\"${RESSOURCE_PATH}\"") +add_compile_definitions("USE_DRAGONNET") + +add_compile_options(-Wall -Wextra -Werror -fmax-errors=4) + link_libraries( pthread m z ) -set(DEPS_DIR "${CMAKE_SOURCE_DIR}/../deps/") +include_directories(SYSTEM ${DEPS_DIR}) +include_directories(BEFORE ${CMAKE_SOURCE_DIR}) -include_directories(SYSTEM - ${DEPS_DIR} -) - -include_directories(BEFORE - ${CMAKE_SOURCE_DIR} -) +# System specific options if ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") link_directories("/usr/local/lib") @@ -37,20 +48,22 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") include_directories("/usr/X11R6/include") endif() -add_compile_options(-Wall -Wextra -Werror) +# Common sources -set(DEPS_SOURCES - "${DEPS_DIR}/dragontype/array.c" - "${DEPS_DIR}/dragontype/bintree.c" - "${DEPS_DIR}/dragontype/list.c" - "${DEPS_DIR}/dragontype/number.c" - "${DEPS_DIR}/dragontype/queue.c" +set(COMMON_SOURCES + "${DEPS_DIR}/dragonnet/addr.c" + "${DEPS_DIR}/dragonnet/listen.c" + "${DEPS_DIR}/dragonnet/peer.c" + "${DEPS_DIR}/dragonnet/recv.c" + "${DEPS_DIR}/dragonnet/recv_thread.c" + "${DEPS_DIR}/dragonnet/send.c" "${DEPS_DIR}/dragonport/asprintf.c" + "${DEPS_DIR}/dragonstd/array.c" + "${DEPS_DIR}/dragonstd/bintree.c" + "${DEPS_DIR}/dragonstd/list.c" + "${DEPS_DIR}/dragonstd/queue.c" + "${DEPS_DIR}/linenoise/linenoise.c" "${DEPS_DIR}/perlin/perlin.c" -) - -set(COMMON_SOURCES - ${DEPS_SOURCES} config.c day.c environment.c @@ -58,15 +71,18 @@ set(COMMON_SOURCES node.c perlin.c signal_handlers.c + types.c util.c ) +# Client + add_executable(Dragonblocks ${COMMON_SOURCES} client/blockmesh.c client/camera.c client/client.c - client/client_commands.c + client/client_auth.c client/client_config.c client/client_map.c client/client_node.c @@ -100,15 +116,17 @@ target_include_directories(Dragonblocks PUBLIC ${FREETYPE_INCLUDE_DIRS} ) +# Server + add_executable(DragonblocksServer ${COMMON_SOURCES} server/biomes.c server/database.c server/mapgen.c server/server.c - server/server_commands.c server/server_config.c server/server_map.c + server/server_player.c server/trees.c server/voxelctx.c ) @@ -117,13 +135,27 @@ target_link_libraries(DragonblocksServer sqlite3 ) -add_custom_target(version +# Version + +add_custom_target(Version COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -P ${CMAKE_SOURCE_DIR}/version.cmake ) -add_dependencies(Dragonblocks version) -add_dependencies(DragonblocksServer version) +add_dependencies(Dragonblocks Version) +add_dependencies(DragonblocksServer Version) -if (CMAKE_BUILD_TYPE STREQUAL "Release") - add_compile_definitions(RELEASE) -endif() +# Types + +add_custom_command( + OUTPUT "${CMAKE_SOURCE_DIR}/types.c" "${CMAKE_SOURCE_DIR}/types.h" + COMMAND "${CMAKE_SOURCE_DIR}/mktypes.sh" + MAIN_DEPENDENCY "${CMAKE_SOURCE_DIR}/types.def" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) + +add_custom_target(DragonnetTypes + DEPENDS "${CMAKE_SOURCE_DIR}/types.c" "${CMAKE_SOURCE_DIR}/types.h" +) + +add_dependencies(Dragonblocks DragonnetTypes) +add_dependencies(DragonblocksServer DragonnetTypes) diff --git a/src/client/camera.h b/src/client/camera.h index e5f7f45..bc7d57c 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include "types.h" extern struct Camera { diff --git a/src/client/client.c b/src/client/client.c index ac24c2f..88bcded 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -2,159 +2,111 @@ #include #include #include -#include -#include #include "client/client.h" +#include "client/client_auth.h" #include "client/client_map.h" #include "client/client_player.h" #include "client/game.h" #include "client/input.h" +#include "day.h" #include "signal_handlers.h" +#include "perlin.h" +#include "types.h" #include "util.h" -static Client client; +DragonnetPeer *client; -void client_disconnect(bool send, const char *detail) +static bool finished = false; + +static bool on_recv(unused DragonnetPeer *peer, DragonnetTypeId type, unused void *pkt) { - pthread_mutex_lock(&client.mtx); - if (client.state != CS_DISCONNECTED) { - if (send) - write_u32(client.fd, SC_DISCONNECT); - - client.state = CS_DISCONNECTED; - printf("Disconnected %s%s%s\n", INBRACES(detail)); - close(client.fd); - } - pthread_mutex_unlock(&client.mtx); + while (client_auth.state == AUTH_INIT) + ; + + return (client_auth.state == AUTH_WAIT) == (type == DRAGONNET_TYPE_ToClientAuth); } -void client_send_position(v3f64 pos) +static void on_disconnect(unused DragonnetPeer *peer) { - pthread_mutex_lock(&client.mtx); - (void) (write_u32(client.fd, SC_POS) && write_v3f64(client.fd, pos)); - pthread_mutex_unlock(&client.mtx); + interrupted = true; + while (! finished) + ; } -#include "network.c" - -static void *reciever_thread(unused void *arg) +static void on_ToClientAuth(unused DragonnetPeer *peer, ToClientAuth *pkt) { - handle_packets(&client); + if (pkt->success) { + client_auth.state = AUTH_SUCCESS; + printf("Authenticated successfully\n"); + } else { + client_auth.state = AUTH_INIT; + printf("Authentication failed, please try again\n"); + } +} - if (errno != EINTR) - client_disconnect(false, "network error"); +static void on_ToClientBlock(unused DragonnetPeer *peer, ToClientBlock *pkt) +{ + MapBlock *block = map_get_block(client_map.map, pkt->pos, true); - return NULL; + map_deserialize_block(block, pkt->data); + client_map_block_received(block); } -static bool client_name_prompt() +static void on_ToClientInfo(unused DragonnetPeer *peer, ToClientInfo *pkt) { - printf("Enter name: "); - fflush(stdout); - char name[PLAYER_NAME_MAX]; - if (scanf("%s", name) == EOF) - return false; - client.name = strdup(name); - pthread_mutex_lock(&client.mtx); - if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) { - client.state = CS_AUTH; - printf("Authenticating...\n"); - } - pthread_mutex_unlock(&client.mtx); - return true; + client_map_set_simulation_distance(pkt->simulation_distance); + seed = pkt->seed; } -static bool client_authenticate() +static void on_ToClientPos(unused DragonnetPeer *peer, ToClientPos *pkt) { - for ever { - switch (client.state) { - case CS_CREATED: - if (client_name_prompt()) - break; - else - return false; - case CS_AUTH: - if (interrupted) - return false; - else - sched_yield(); - break; - case CS_ACTIVE: - return true; - case CS_DISCONNECTED: - return false; - } - } - return false; + client_player_set_position(pkt->pos); } -static bool client_start(int fd) +static void on_ToClientTimeOfDay(unused DragonnetPeer *peer, ToClientTimeOfDay *pkt) { - client.fd = fd; - pthread_mutex_init(&client.mtx, NULL); - client.state = CS_CREATED; - client.name = NULL; - - client_map_init(&client); - client_player_init(); - - pthread_t recv_thread; - pthread_create(&recv_thread, NULL, &reciever_thread, NULL); - - bool return_value = client_authenticate() && game(&client); - - if (client.state != CS_DISCONNECTED) - client_disconnect(true, NULL); - - if (client.name) - free(client.name); - - pthread_join(recv_thread, NULL); - - client_player_deinit(); - client_map_deinit(); - - pthread_mutex_destroy(&client.mtx); - - return return_value; + set_time_of_day(pkt->time_of_day); } int main(int argc, char **argv) { - program_name = argv[0]; - - if (argc < 3) - internal_error("missing address or port"); - - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = 0, - .ai_flags = AI_NUMERICSERV, - }; - - struct addrinfo *info = NULL; - - int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info); + if (argc < 2) { + fprintf(stderr, "Missing address\n"); + return EXIT_FAILURE; + } - if (gai_state != 0) - internal_error(gai_strerror(gai_state)); + if (! (client = dragonnet_connect(argv[1]))) { + fprintf(stderr, "Failed to connect to server\n"); + return EXIT_FAILURE; + } - int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + client->on_disconnect = &on_disconnect; + client->on_recv = &on_recv; + client->on_recv_type[DRAGONNET_TYPE_ToClientAuth ] = (void *) &on_ToClientAuth; + client->on_recv_type[DRAGONNET_TYPE_ToClientBlock ] = (void *) &on_ToClientBlock; + client->on_recv_type[DRAGONNET_TYPE_ToClientInfo ] = (void *) &on_ToClientInfo; + client->on_recv_type[DRAGONNET_TYPE_ToClientPos ] = (void *) &on_ToClientPos; + client->on_recv_type[DRAGONNET_TYPE_ToClientTimeOfDay] = (void *) &on_ToClientTimeOfDay; - if (fd == -1) - syscall_error("socket"); + signal_handlers_init(); + client_map_init(); + client_player_init(); + dragonnet_peer_run(client); - if (connect(fd, info->ai_addr, info->ai_addrlen) == -1) - syscall_error("connect"); + if (! client_auth_init()) + return EXIT_FAILURE; - char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr); - printf("Connected to %s\n", addrstr); - free(addrstr); + if (! game()) + return EXIT_FAILURE; - freeaddrinfo(info); + dragonnet_peer_shutdown(client); + client_auth_deinit(); + client_player_deinit(); + client_map_deinit(); - signal_handlers_init(); + pthread_t recv_thread = client->recv_thread; + finished = true; + pthread_join(recv_thread, NULL); - return client_start(fd) ? EXIT_SUCCESS : EXIT_FAILURE; + return EXIT_SUCCESS; } diff --git a/src/client/client.h b/src/client/client.h index bca96f8..51ad358 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -1,29 +1,8 @@ #ifndef _CLIENT_H_ #define _CLIENT_H_ -#include -#include -#include -#include "client/client_commands.h" -#include "client/scene.h" -#include "server/server_commands.h" -#include "network.h" +#include -#ifdef RELEASE - #define RESSOURCEPATH "" -#else - #define RESSOURCEPATH "../" -#endif - -typedef struct Client -{ - int fd; - pthread_mutex_t mtx; - ClientState state; - char *name; -} Client; - -void client_disconnect(bool send, const char *detail); -void client_send_position(v3f64 pos); +extern DragonnetPeer *client; #endif diff --git a/src/client/client_auth.c b/src/client/client_auth.c new file mode 100644 index 0000000..d78d992 --- /dev/null +++ b/src/client/client_auth.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include "client.h" +#include "client_auth.h" +#include "signal_handlers.h" +#include "types.h" + +struct ClientAuth client_auth; + +static bool name_prompt() +{ + if (! (client_auth.name = linenoise("Enter name: "))) + return false; + + dragonnet_peer_send_ToServerAuth(client, &(ToServerAuth) { + .name = client_auth.name, + }); + + printf("Authenticating as %s...\n", client_auth.name); + client_auth.state = AUTH_WAIT; + + return true; +} + +bool client_auth_init() +{ + client_auth.state = AUTH_INIT; + + while (! interrupted) { + switch (client_auth.state) { + case AUTH_INIT: + if (name_prompt()) + break; + else + return false; + + case AUTH_WAIT: + sched_yield(); + break; + + case AUTH_SUCCESS: + return true; + } + } + + return false; +} + +void client_auth_deinit() +{ + linenoiseFree(client_auth.name); +} diff --git a/src/client/client_auth.h b/src/client/client_auth.h new file mode 100644 index 0000000..ba14942 --- /dev/null +++ b/src/client/client_auth.h @@ -0,0 +1,21 @@ +#ifndef _CLIENT_AUTH_H_ +#define _CLIENT_AUTH_H_ + +typedef enum +{ + AUTH_INIT, + AUTH_WAIT, + AUTH_SUCCESS, +} ClientAuthState; + +extern struct ClientAuth +{ + char *name; + ClientAuthState state; +} client_auth; + +bool client_auth_init(); +void client_auth_assert_state(ClientAuthState state, const char *pkt); +void client_auth_deinit(); + +#endif diff --git a/src/client/client_commands.c b/src/client/client_commands.c deleted file mode 100644 index 63bce0d..0000000 --- a/src/client/client_commands.c +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include -#include -#include "client/client.h" -#include "client/client_map.h" -#include "client/client_player.h" -#include "day.h" -#include "perlin.h" -#include "util.h" - -static bool disconnect_handler(unused Client *client, bool good) -{ - if (good) - client_disconnect(false, NULL); - return true; -} - -static bool auth_handler(Client *client, bool good) -{ - u8 success; - if (! read_u8(client->fd, &success)) - return false; - - if (! good) - return true; - - if (success) { - printf("Authenticated successfully\n"); - client->state = CS_ACTIVE; - } else { - printf("Authentication failed, please try again\n"); - client->state = CS_CREATED; - } - - return true; -} - -static bool block_handler(Client *client, bool good) -{ - v3s32 pos; - - if (! read_v3s32(client->fd, &pos)) - return false; - - u64 size; - - if (! read_u64(client->fd, &size)) - return false; - - if (size > 1 << 16) - return false; - - u64 rawsize; - - if (! read_u64(client->fd, &rawsize)) - return false; - - char data[size]; - if (! read_full(client->fd, data, size)) - return false; - - MapBlock *block; - - if (good) - block = map_get_block(client_map.map, pos, true); - else - block = map_allocate_block(pos); - - bool ret = map_deserialize_block(block, data, size, rawsize); - - if (good) - client_map_block_received(block); - else - map_free_block(block); - - return ret; -} - -static bool info_handler(Client *client, bool good) -{ - u32 simulation_distance; - s32 server_seed; - - if (! (read_u32(client->fd, &simulation_distance) && read_s32(client->fd, &server_seed))) - return false; - - if (good) { - client_map_set_simulation_distance(simulation_distance); - seed = server_seed; - } - - return true; -} - -static bool setpos_handler(Client *client, bool good) -{ - v3f64 pos; - - if (! read_v3f64(client->fd, &pos)) - return false; - - if (good) - client_player_set_position(pos); - - return true; -} - -static bool timeofday_handler(Client *client, bool good) -{ - u64 time_of_day; - - if (! read_u64(client->fd, &time_of_day)) - return false; - - if (good) - set_time_of_day(time_of_day); - - return true; -} - -CommandHandler command_handlers[CLIENT_COMMAND_COUNT] = { - {0}, - {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_AUTH | CS_ACTIVE}, - {&auth_handler, "AUTH", CS_AUTH}, - {&block_handler, "BLOCK", CS_ACTIVE}, - {&info_handler, "INFO", CS_ACTIVE}, - {&setpos_handler, "SETPOS", CS_ACTIVE}, - {&timeofday_handler, "TIMEOFDAY", CS_ACTIVE}, -}; diff --git a/src/client/client_commands.h b/src/client/client_commands.h deleted file mode 100644 index a209fea..0000000 --- a/src/client/client_commands.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _CLIENT_COMMANDS_H_ -#define _CLIENT_COMMANDS_H_ - -typedef enum -{ - CLIENT_COMMAND_NULL, - CC_DISCONNECT, - CC_AUTH, - CC_BLOCK, - CC_INFO, - CC_SETPOS, - CC_TIMEOFDAY, - CLIENT_COMMAND_COUNT -} ClientCommand; - -#ifdef _SERVER_H_ -typedef ClientCommand RemoteCommand; -#endif - -#ifdef _CLIENT_H_ -typedef ClientCommand HostCommand; -#define HOST_COMMAND_COUNT CLIENT_COMMAND_COUNT -#endif - -#endif diff --git a/src/client/client_map.c b/src/client/client_map.c index 4307774..23952a1 100644 --- a/src/client/client_map.c +++ b/src/client/client_map.c @@ -9,7 +9,6 @@ #define MAX_BLOCK_REQUESTS 4 struct ClientMap client_map; -Client *client; // meshgen functions @@ -48,9 +47,9 @@ static void *meshgen_thread(unused void *arg) // send block request command to server static void request_position(v3s32 pos) { - pthread_mutex_lock(&client->mtx); - (void) (write_u32(client->fd, SC_REQUEST_BLOCK) && write_v3s32(client->fd, pos)); - pthread_mutex_unlock(&client->mtx); + dragonnet_peer_send_ToServerRequestBlock(client, &(ToServerRequestBlock) { + .pos = pos + }); } // mapblock synchronisation step @@ -156,10 +155,8 @@ static bool on_get_block(MapBlock *block, bool create) // public functions // ClientMap singleton constructor -void client_map_init(Client *cli) +void client_map_init() { - client = cli; - client_map.map = map_create((MapCallbacks) { .create_block = &on_create_block, .delete_block = &on_delete_block, diff --git a/src/client/client_map.h b/src/client/client_map.h index b0fdefb..b9e0616 100644 --- a/src/client/client_map.h +++ b/src/client/client_map.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include "map.h" #include "client/object.h" #define NUM_MESHGEN_THREADS 4 diff --git a/src/client/client_node.c b/src/client/client_node.c index 22b7c65..18283eb 100644 --- a/src/client/client_node.c +++ b/src/client/client_node.c @@ -52,7 +52,7 @@ static void render_grass(v3s32 pos, unused MapNode *node, Vertex3D *vertex, unus hum_max = 0.33f; temp_max = 0.45f; - f32 temp_f = clamp(0.3f - get_temperature(pos), 0.0f, 0.3f) / 0.3f; + f32 temp_f = f64_clamp(0.3f - get_temperature(pos), 0.0f, 0.3f) / 0.3f; vertex->color = hsl_to_rgb((v3f32) {(get_humidity(pos) * (hum_max - hum_min) + hum_min) * (1.0f - temp_f) + temp_max * temp_f, 1.0f, 0.5f}); } @@ -71,7 +71,7 @@ static void render_hsl(unused v3s32 pos, MapNode *node, Vertex3D *vertex, unused ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { // unknown { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/unknown.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/unknown.png"), .visibility = NV_SOLID, .mipmap = true, .render = NULL, @@ -85,28 +85,28 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { }, // grass { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/grass.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/grass.png"), .visibility = NV_SOLID, .mipmap = true, .render = &render_grass, }, // dirt { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/dirt.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/dirt.png"), .visibility = NV_SOLID, .mipmap = true, .render = NULL, }, // stone { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/stone.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/stone.png"), .visibility = NV_SOLID, .mipmap = true, .render = &render_stone, }, // snow { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/snow.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/snow.png"), .visibility = NV_SOLID, .mipmap = true, .render = NULL, @@ -114,7 +114,7 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { // oak wood { .tiles = { - .paths = {RESSOURCEPATH "textures/oak_wood.png", RESSOURCEPATH "textures/oak_wood_top.png", NULL, NULL, NULL, NULL}, + .paths = {RESSOURCE_PATH "textures/oak_wood.png", RESSOURCE_PATH "textures/oak_wood_top.png", NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 1, 1}, .textures = {NULL}, }, @@ -124,7 +124,7 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { }, // oak leaves { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/oak_leaves.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/oak_leaves.png"), .visibility = NV_SOLID, .mipmap = true, .render = &render_hsl, @@ -132,7 +132,7 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { // pine wood { .tiles = { - .paths = {RESSOURCEPATH "textures/pine_wood.png", RESSOURCEPATH "textures/pine_wood_top.png", NULL, NULL, NULL, NULL}, + .paths = {RESSOURCE_PATH "textures/pine_wood.png", RESSOURCE_PATH "textures/pine_wood_top.png", NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 1, 1}, .textures = {NULL}, }, @@ -142,7 +142,7 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { }, // pine leaves { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/pine_leaves.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/pine_leaves.png"), .visibility = NV_CLIP, .mipmap = true, .render = &render_hsl, @@ -150,7 +150,7 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { // palm wood { .tiles = { - .paths = {RESSOURCEPATH "textures/palm_wood.png", RESSOURCEPATH "textures/palm_wood_top.png", NULL, NULL, NULL, NULL}, + .paths = {RESSOURCE_PATH "textures/palm_wood.png", RESSOURCE_PATH "textures/palm_wood_top.png", NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 1, 1}, .textures = {NULL}, }, @@ -160,35 +160,35 @@ ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = { }, // palm leaves { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/palm_leaves.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/palm_leaves.png"), .visibility = NV_SOLID, .mipmap = true, .render = &render_hsl, }, // sand { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/sand.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/sand.png"), .visibility = NV_SOLID, .mipmap = true, .render = NULL, }, // water { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/water.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/water.png"), .visibility = NV_BLEND, .mipmap = true, .render = NULL, }, // lava { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/lava.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/lava.png"), .visibility = NV_BLEND, .mipmap = true, .render = NULL, }, // vulcano_stone { - .tiles = TILES_SIMPLE(RESSOURCEPATH "textures/vulcano_stone.png"), + .tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/vulcano_stone.png"), .visibility = NV_SOLID, .mipmap = true, .render = NULL, diff --git a/src/client/client_player.c b/src/client/client_player.c index d0418db..a5a69c1 100644 --- a/src/client/client_player.c +++ b/src/client/client_player.c @@ -15,7 +15,9 @@ struct ClientPlayer client_player; static void update_pos() { camera_set_position((v3f32) {client_player.pos.x, client_player.pos.y + client_player.eye_height, client_player.pos.z}); - client_send_position(client_player.pos); + dragonnet_peer_send_ToServerPos(client, &(ToServerPos) { + .pos = client_player.pos, + }); client_player.obj->pos = (v3f32) {client_player.pos.x, client_player.pos.y, client_player.pos.z}; object_transform(client_player.obj); @@ -100,7 +102,7 @@ void client_player_add_to_scene() client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6}; client_player.obj->visible = false; - object_set_texture(client_player.obj, texture_load(RESSOURCEPATH "textures/player.png", true)); + object_set_texture(client_player.obj, texture_load(RESSOURCE_PATH "textures/player.png", true)); for (int f = 0; f < 6; f++) { for (int v = 0; v < 6; v++) { @@ -194,7 +196,7 @@ void client_player_tick(f64 dtime) } \ } \ } \ - a ## _physics_done: (void) 0;\ + a ## _physics_done: (void) 0; \ } PHYSICS(x, y, z) diff --git a/src/client/client_player.h b/src/client/client_player.h index 192b6fe..0de19b9 100644 --- a/src/client/client_player.h +++ b/src/client/client_player.h @@ -2,9 +2,9 @@ #define _CLIENT_PLAYER_H_ #include -#include #include "client/client.h" #include "client/object.h" +#include "types.h" extern struct ClientPlayer { diff --git a/src/client/facecache.c b/src/client/facecache.c index 09ea7d6..f08854d 100644 --- a/src/client/facecache.c +++ b/src/client/facecache.c @@ -1,5 +1,5 @@ #include -#include +#include #include "client/facecache.h" static struct diff --git a/src/client/facecache.h b/src/client/facecache.h index 2900cd5..847b739 100644 --- a/src/client/facecache.h +++ b/src/client/facecache.h @@ -2,7 +2,7 @@ #define _FACECACHE_H_ #include -#include +#include "types.h" v3s32 facecache_face(size_t i, v3s32 *base); size_t facecache_count(u32 size); diff --git a/src/client/font.c b/src/client/font.c index 1c7684d..18bdb82 100644 --- a/src/client/font.c +++ b/src/client/font.c @@ -3,10 +3,10 @@ #include FT_FREETYPE_H #include "client/client.h" #include "client/font.h" +#include "client/texture.h" #define NUM_CHARS 128 - typedef struct { Texture *texture; @@ -66,7 +66,7 @@ bool font_init() return false; } - if (FT_New_Face(font.library, RESSOURCEPATH "fonts/Minecraftia.ttf", 0, &font.face)) { + if (FT_New_Face(font.library, RESSOURCE_PATH "fonts/Minecraftia.ttf", 0, &font.face)) { fprintf(stderr, "Failed to load Minecraftia.ttf\n"); return false; } diff --git a/src/client/font.h b/src/client/font.h index 2143126..def7410 100644 --- a/src/client/font.h +++ b/src/client/font.h @@ -4,6 +4,7 @@ #include #include #include "client/mesh.h" +#include "types.h" typedef struct { diff --git a/src/client/frustum.h b/src/client/frustum.h index 4dd7477..fa8eba5 100644 --- a/src/client/frustum.h +++ b/src/client/frustum.h @@ -3,7 +3,7 @@ #include #include -#include +#include "types.h" void frustum_update(mat4x4 view_proj); bool frustum_is_visible(aabb3f32 box); diff --git a/src/client/game.c b/src/client/game.c index 822fe95..1ea39b3 100644 --- a/src/client/game.c +++ b/src/client/game.c @@ -14,6 +14,7 @@ #include "client/font.h" #include "client/gui.h" #include "client/input.h" +#include "client/scene.h" #include "client/sky.h" #include "client/window.h" #include "day.h" @@ -33,7 +34,7 @@ static void crosshair_init() .scale_type = GST_IMAGE, .affect_parent_scale = false, .text = NULL, - .image = texture_load(RESSOURCEPATH "textures/crosshair.png", false), + .image = texture_load(RESSOURCE_PATH "textures/crosshair.png", false), .text_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f}, .bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f}, }); @@ -58,7 +59,7 @@ static void render(f64 dtime) gui_render(); } -static void game_loop(Client *client) +static void game_loop() { f64 fps_update_timer = 1.0f; int frames = 0; @@ -66,7 +67,7 @@ static void game_loop(Client *client) struct timespec ts, ts_old; clock_gettime(CLOCK_REALTIME, &ts_old); - while (! glfwWindowShouldClose(window.handle) && client->state != CS_DISCONNECTED && ! interrupted) { + while (! glfwWindowShouldClose(window.handle) && ! interrupted) { clock_gettime(CLOCK_REALTIME, &ts); f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1.0e9; ts_old = ts; @@ -93,7 +94,7 @@ static void game_loop(Client *client) } } -bool game(Client *client) +bool game() { window_width = 1250; window_height = 750; @@ -145,7 +146,7 @@ bool game(Client *client) client_player_add_to_scene(); - game_loop(client); + game_loop(); client_map_stop(); diff --git a/src/client/game.h b/src/client/game.h index d28a4c5..b6c04bd 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -1,9 +1,7 @@ #ifndef _GAME_H_ #define _GAME_H_ -#include "client/client.h" - -bool game(Client *client); +bool game(); char *take_screenshot(); void game_on_resize(int width, int height); diff --git a/src/client/gui.c b/src/client/gui.c index 5fc58b7..11fa50a 100644 --- a/src/client/gui.c +++ b/src/client/gui.c @@ -127,7 +127,7 @@ bool gui_init() { // initialize background pipeline - if (! shader_program_create(RESSOURCEPATH "shaders/gui/background", &gui.background_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/gui/background", &gui.background_prog, NULL)) { fprintf(stderr, "Failed to create GUI background shader program\n"); return false; } @@ -147,7 +147,7 @@ bool gui_init() // initialize image pipeline - if (! shader_program_create(RESSOURCEPATH "shaders/gui/image", &gui.image_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/gui/image", &gui.image_prog, NULL)) { fprintf(stderr, "Failed to create GUI image shader program\n"); return false; } @@ -166,7 +166,7 @@ bool gui_init() // initialize font pipeline - if (! shader_program_create(RESSOURCEPATH "shaders/gui/font", &gui.font_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/gui/font", &gui.font_prog, NULL)) { fprintf(stderr, "Failed to create GUI font shader program\n"); return false; } diff --git a/src/client/gui.h b/src/client/gui.h index b48d210..7fd1844 100644 --- a/src/client/gui.h +++ b/src/client/gui.h @@ -3,11 +3,11 @@ #include #include -#include -#include -#include +#include +#include #include "client/font.h" #include "client/texture.h" +#include "types.h" typedef enum { diff --git a/src/client/input.c b/src/client/input.c index 763629d..a862017 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -49,7 +49,7 @@ void input_on_cursor_pos(double current_x, double current_y) client_player.pitch -= (f32) delta_y * M_PI / 180.0f / 8.0f; client_player.yaw = fmod(client_player.yaw + M_PI * 2.0f, M_PI * 2.0f); - client_player.pitch = fmax(fmin(client_player.pitch, M_PI / 2.0f - 0.01f), -M_PI / 2.0f + 0.01f); + client_player.pitch = f32_clamp(client_player.pitch, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f); camera_set_angle(client_player.yaw, client_player.pitch); diff --git a/src/client/input.h b/src/client/input.h index 3789050..fd27cf6 100644 --- a/src/client/input.h +++ b/src/client/input.h @@ -1,7 +1,7 @@ #ifndef _INPUT_H_ #define _INPUT_H_ -#include +#include "types.h" void input_tick(f64 dtime); void input_init(); diff --git a/src/client/object.h b/src/client/object.h index 549db74..a5152d2 100644 --- a/src/client/object.h +++ b/src/client/object.h @@ -6,11 +6,11 @@ #include #include #include -#include -#include +#include #include "client/mesh.h" #include "client/texture.h" #include "client/vertex.h" +#include "types.h" typedef struct { GLfloat x, y, z; diff --git a/src/client/scene.c b/src/client/scene.c index a318b28..d2d42ca 100644 --- a/src/client/scene.c +++ b/src/client/scene.c @@ -32,7 +32,7 @@ bool scene_init() client_config.render_distance ); - if (! shader_program_create(RESSOURCEPATH "shaders/3d", &scene.prog, shader_defs)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/3d", &scene.prog, shader_defs)) { fprintf(stderr, "Failed to create 3D shader program\n"); return false; } diff --git a/src/client/scene.h b/src/client/scene.h index bb8fd20..49a786d 100644 --- a/src/client/scene.h +++ b/src/client/scene.h @@ -4,9 +4,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include "types.h" #include "client/object.h" extern struct Scene diff --git a/src/client/sky.c b/src/client/sky.c index 248a4b8..2867298 100644 --- a/src/client/sky.c +++ b/src/client/sky.c @@ -106,7 +106,7 @@ bool sky_init() { // skybox - if (! shader_program_create(RESSOURCEPATH "shaders/sky/skybox", &sky.skybox_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/sky/skybox", &sky.skybox_prog, NULL)) { fprintf(stderr, "Failed to create skybox shader program\n"); return false; } @@ -114,8 +114,8 @@ bool sky_init() sky.skybox_loc_VP = glGetUniformLocation(sky.skybox_prog, "VP"); sky.skybox_loc_daylight = glGetUniformLocation(sky.skybox_prog, "daylight"); - sky.skybox_textures[0] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/day"); - sky.skybox_textures[1] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/night"); + sky.skybox_textures[0] = texture_create_cubemap(RESSOURCE_PATH "textures/skybox/day"); + sky.skybox_textures[1] = texture_create_cubemap(RESSOURCE_PATH "textures/skybox/night"); GLint texture_indices[2]; for (GLint i = 0; i < 2; i++) @@ -142,14 +142,14 @@ bool sky_init() // sun - if (! shader_program_create(RESSOURCEPATH "shaders/sky/sun", &sky.sun_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/sky/sun", &sky.sun_prog, NULL)) { fprintf(stderr, "Failed to create sun shader program\n"); return false; } sky.sun_loc_MVP = glGetUniformLocation(sky.sun_prog, "MVP"); - sky.sun_texture = texture_load(RESSOURCEPATH "textures/sun.png", false); + sky.sun_texture = texture_load(RESSOURCE_PATH "textures/sun.png", false); sky.sun_mesh = mesh_create(); sky.sun_mesh->textures = &sky.sun_texture->id; @@ -162,7 +162,7 @@ bool sky_init() // clouds - if (! shader_program_create(RESSOURCEPATH "shaders/sky/clouds", &sky.clouds_prog, NULL)) { + if (! shader_program_create(RESSOURCE_PATH "shaders/sky/clouds", &sky.clouds_prog, NULL)) { fprintf(stderr, "Failed to create clouds shader program\n"); return false; } diff --git a/src/client/texture.c b/src/client/texture.c index b2fbd4c..1036a91 100644 --- a/src/client/texture.c +++ b/src/client/texture.c @@ -1,7 +1,7 @@ #define STB_IMAGE_IMPLEMENTATION #include #include -#include +#include #include "client/client_config.h" #include "client/texture.h" #include "util.h" diff --git a/src/day.c b/src/day.c index 0cc5500..24b6b4b 100644 --- a/src/day.c +++ b/src/day.c @@ -30,7 +30,7 @@ f64 get_sun_angle() f64 get_daylight() { - return clamp(cos(get_sun_angle()) * 2.0 + 0.5, 0.0, 1.0); + return f64_clamp(cos(get_sun_angle()) * 2.0 + 0.5, 0.0, 1.0); } void split_time_of_day(int *hours, int *minutes) diff --git a/src/day.h b/src/day.h index c2bc653..b35e12e 100644 --- a/src/day.h +++ b/src/day.h @@ -2,7 +2,7 @@ #define _DAY_H_ #include -#include +#include "types.h" #define MINUTES_PER_HOUR 60 #define HOURS_PER_DAY 24 #define MINUTES_PER_DAY (HOURS_PER_DAY * MINUTES_PER_HOUR) diff --git a/src/debug.sh b/src/debug.sh index 32fa0c1..98d38c4 100755 --- a/src/debug.sh +++ b/src/debug.sh @@ -21,12 +21,12 @@ end " echo "$COMMON -run ::1 4000 < $DEBUG_DIR/name +run \"[::1]:4000\" < $DEBUG_DIR/name " > $DEBUG_DIR/client_script echo "$COMMON set print thread-events off -run 4000 +run \"[::1]:4000\" " > $DEBUG_DIR/server_script kitty --detach -e bash -c " diff --git a/src/environment.h b/src/environment.h index bacda15..1de120c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -1,7 +1,7 @@ #ifndef _ENVIRONMENT_H_ #define _ENVIRONMENT_H_ -#include +#include "types.h" f64 get_humidity(v3s32 pos); f64 get_temperature(v3s32 pos); diff --git a/src/map.c b/src/map.c index 59097b8..a9a83be 100644 --- a/src/map.c +++ b/src/map.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "map.h" #include "util.h" @@ -131,7 +130,7 @@ MapBlock *map_allocate_block(v3s32 pos) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&block->mtx, &attr); - ITERATE_MAPBLOCK block->data[x][y][z] = map_node_create(NODE_UNKNOWN, NULL, 0); + ITERATE_MAPBLOCK block->data[x][y][z] = map_node_create(NODE_UNKNOWN, (Blob) {0, NULL}); return block; } @@ -144,77 +143,48 @@ void map_free_block(MapBlock *block) free(block); } -void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr, size_t *rawsizeptr) +Blob map_serialize_block(MapBlock *block) { - unsigned char *uncompressed = NULL; - size_t uncompressed_size = 0; + SerializedMapBlock block_data; ITERATE_MAPBLOCK { - MapNode node = block->data[x][y][z]; - NodeDefinition *def = &node_definitions[node.type]; + MapNode *node = &block->data[x][y][z]; + SerializedMapNode *node_data = &block_data.raw.nodes[x][y][z]; - u32 type = htobe32(node.type); - buffer_write(&uncompressed, &uncompressed_size, &type, sizeof(u32)); + *node_data = (SerializedMapNode) { + .type = node->type, + .data = { + .siz = 0, + .data = NULL, + }, + }; - unsigned char *data_buffer = NULL; - size_t data_bufsiz = 0; + NodeDefinition *def = &node_definitions[node->type]; if (def->serialize) - def->serialize(&node, &data_buffer, &data_bufsiz); - - u16 data_size = htobe16(data_bufsiz); - buffer_write(&uncompressed, &uncompressed_size, &data_size, sizeof(u16)); - buffer_write(&uncompressed, &uncompressed_size, data_buffer, data_bufsiz); - - if (data_buffer) - free(data_buffer); + def->serialize(&node_data->data, node->data); } - my_compress(uncompressed, uncompressed_size, dataptr, sizeptr); - *rawsizeptr = uncompressed_size; + Blob buffer = {0, NULL}; + SerializedMapBlock_write(&buffer, &block_data); + SerializedMapBlock_free(&block_data); - if (uncompressed) - free(uncompressed); + return buffer; } -bool map_deserialize_block(MapBlock *block, const char *data, size_t size, size_t rawsize) +bool map_deserialize_block(MapBlock *block, Blob buffer) { - unsigned char decompressed[rawsize]; - size_t decompressed_size = rawsize; - - if (! my_decompress(data, size, decompressed, decompressed_size)) - return false; - - unsigned char *ptr = decompressed; - - ITERATE_MAPBLOCK { - // node type - u32 *type_ptr = buffer_read(&ptr, &decompressed_size, sizeof(u32)); - - if (! type_ptr) - return false; + // it's important to copy Blobs that have been malloc'd before reading from them + // because reading from a Blob modifies its data and size pointer, + // but does not free anything + SerializedMapBlock block_data = {0}; + bool success = SerializedMapBlock_read(&buffer, &block_data); - u32 type = be32toh(*type_ptr); - - // data size - u16 *data_size_ptr = buffer_read(&ptr, &decompressed_size, sizeof(u16)); - - if (! data_size_ptr) - return false; - - u16 data_size = be16toh(*data_size_ptr); - - // data - void *data = buffer_read(&ptr, &decompressed_size, data_size); - - if (! data && data_size) - return false; - - // set node - block->data[x][y][z] = map_node_create(type, data, data_size); - } + if (success) ITERATE_MAPBLOCK + block->data[x][y][z] = map_node_create(block_data.raw.nodes[x][y][z].type, block_data.raw.nodes[x][y][z].data); - return true; + SerializedMapBlock_free(&block_data); + return success; } v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset) @@ -230,7 +200,7 @@ MapNode map_get_node(Map *map, v3s32 pos) v3s32 blockpos = map_node_to_block_pos(pos, &offset); MapBlock *block = map_get_block(map, blockpos, false); if (! block) - return map_node_create(NODE_UNLOADED, NULL, 0); + return map_node_create(NODE_UNLOADED, (Blob) {0, NULL}); return block->data[offset.x][offset.y][offset.z]; } @@ -251,7 +221,7 @@ void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg) } } -MapNode map_node_create(Node type, void *data, size_t size) +MapNode map_node_create(Node type, Blob buffer) { if (type >= NODE_UNLOADED) type = NODE_UNKNOWN; @@ -265,8 +235,8 @@ MapNode map_node_create(Node type, void *data, size_t size) if (def->create) def->create(&node); - if (def->deserialize && size) - def->deserialize(&node, data, size); + if (def->deserialize) + def->deserialize(&buffer, node.data); return node; } diff --git a/src/map.h b/src/map.h index c8eb972..9e61d0d 100644 --- a/src/map.h +++ b/src/map.h @@ -3,12 +3,11 @@ #include #include -#include -#include -#include +#include +#include +#include "types.h" #include "node.h" -#define MAPBLOCK_SIZE 16 #define ITERATE_MAPBLOCK for (u8 x = 0; x < MAPBLOCK_SIZE; x++) for (u8 y = 0; y < MAPBLOCK_SIZE; y++) for (u8 z = 0; z < MAPBLOCK_SIZE; z++) typedef struct MapNode @@ -61,15 +60,15 @@ MapBlock *map_get_block(Map *map, v3s32 pos, bool create); MapBlock *map_allocate_block(v3s32 pos); void map_free_block(MapBlock *block); -void map_serialize_block(MapBlock *block, char **dataptr, size_t *sizeptr, size_t *rawsizeptr); -bool map_deserialize_block(MapBlock *block, const char *data, size_t size, size_t rawsize); +Blob map_serialize_block(MapBlock *block); +bool map_deserialize_block(MapBlock *block, Blob buffer); v3s32 map_node_to_block_pos(v3s32 pos, v3u8 *offset); MapNode map_get_node(Map *map, v3s32 pos); void map_set_node(Map *map, v3s32 pos, MapNode node, bool create, void *arg); -MapNode map_node_create(Node type, void *data, size_t size); +MapNode map_node_create(Node type, Blob buffer); void map_node_delete(MapNode node); #endif diff --git a/src/mktypes.sh b/src/mktypes.sh new file mode 100755 index 0000000..e89025e --- /dev/null +++ b/src/mktypes.sh @@ -0,0 +1,3 @@ +#! /bin/sh +LUA_PATH="../deps/dragontype/?.lua;../deps/dragontype/?/init.lua" "../deps/dragontype/typegen.lua" + diff --git a/src/network.c b/src/network.c deleted file mode 100644 index f4fb0a5..0000000 --- a/src/network.c +++ /dev/null @@ -1,55 +0,0 @@ -#include - -bool send_command(Client *client, RemoteCommand cmd) -{ - pthread_mutex_lock(&client->mtx); - bool ret = write_u32(client->fd, cmd); - pthread_mutex_unlock(&client->mtx); - return ret; -} - -static bool handle_packets(Client *client) { - while (client->state != CS_DISCONNECTED || ! interrupted) { - struct pollfd pfd = { - .fd = client->fd, - .events = POLLIN, - .revents = 0, - }; - - int pstate = poll(&pfd, 1, 0); - - if (pstate == -1) { - perror("poll"); - break; - } - - if (pstate == 0) { - sched_yield(); - continue; - } - - if (! (pfd.revents & POLLIN)) - return false; - - HostCommand command; - if (! read_u32(client->fd, &command)) - break; - - CommandHandler *handler = NULL; - - if (command < HOST_COMMAND_COUNT) - handler = &command_handlers[command]; - - if (handler && handler->func) { - bool good = client->state & handler->state_flags; - if (! good) - printf("Received %s command, but client is in invalid state: %d\n", handler->name, client->state); - if (! handler->func(client, good)) - break; - } else { - printf("Received invalid command %d\n", command); - } - } - - return client->state == CS_DISCONNECTED || errno == EINTR; -} diff --git a/src/network.h b/src/network.h deleted file mode 100644 index 4ae343d..0000000 --- a/src/network.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _NETWORK_H_ -#define _NETWORK_H_ - -#include -#define PLAYER_NAME_MAX 64 - -typedef enum -{ - CS_CREATED = 0x01, - CS_AUTH = 0x02, - CS_ACTIVE = 0x04, - CS_DISCONNECTED = 0x08, -} ClientState; - -struct Client; - -typedef struct { - bool (*func)(struct Client *client, bool good); - const char *name; - int state_flags; -} CommandHandler; - -extern CommandHandler command_handlers[]; - -bool send_command(struct Client *client, RemoteCommand cmd); - -#endif diff --git a/src/node.c b/src/node.c index 39e60ac..5aeefea 100644 --- a/src/node.c +++ b/src/node.c @@ -1,26 +1,9 @@ +#include "types.h" #include "map.h" #include "node.h" #include "util.h" #include -static void serialize_hsl(MapNode *node, unsigned char **buffer, size_t *bufsiz) -{ - HSLData *node_data = node->data; - buffer_write(buffer, bufsiz, (f32 []) {node_data->color.x, node_data->color.y, node_data->color.z}, sizeof(f32) * 3); -} - -static void deserialize_hsl(MapNode *node, unsigned char *data, size_t size) -{ - HSLData *node_data = node->data; - - f32 *color = buffer_read(&data, &size, sizeof(f32) * 3); - - if (! color) - return; - - *node_data = (HSLData) {.color = {color[0], color[1], color[2]}}; -} - NodeDefinition node_definitions[NODE_UNLOADED] = { // unknown { @@ -82,8 +65,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // oak leaves { @@ -91,8 +74,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // pine wood { @@ -100,8 +83,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // pine leaves { @@ -109,8 +92,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // palm wood { @@ -118,8 +101,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // palm leaves { @@ -127,8 +110,8 @@ NodeDefinition node_definitions[NODE_UNLOADED] = { .data_size = sizeof(HSLData), .create = NULL, .delete = NULL, - .serialize = &serialize_hsl, - .deserialize = &deserialize_hsl, + .serialize = (void *) &HSLData_write, + .deserialize = (void *) &HSLData_read, }, // sand { diff --git a/src/node.h b/src/node.h index 2bcf8e2..2ed4edd 100644 --- a/src/node.h +++ b/src/node.h @@ -2,7 +2,7 @@ #define _NODE_H_ #include -#include +#include "types.h" #define NODE_DEFINITION(type) ((type) < NODE_UNLOADED ? &node_definitions[NODE_UNKNOWN] : &node_definitions[(type)]); @@ -35,14 +35,10 @@ typedef struct size_t data_size; void (*create)(struct MapNode *node); void (*delete)(struct MapNode *node); - void (*serialize)(struct MapNode *node, unsigned char **buffer, size_t *bufsiz); - void (*deserialize)(struct MapNode *node, unsigned char *data, size_t size); + void (*serialize)(Blob *buffer, void *data); + void (*deserialize)(Blob *buffer, void *data); } NodeDefinition; -typedef struct { - v3f32 color; -} HSLData; - extern NodeDefinition node_definitions[]; #endif diff --git a/src/perlin.h b/src/perlin.h index 366a4d9..0213c68 100644 --- a/src/perlin.h +++ b/src/perlin.h @@ -2,7 +2,7 @@ #define _PERLIN_H_ #include -#include +#include "types.h" typedef enum { diff --git a/src/server/biomes.c b/src/server/biomes.c index 4a7834a..9d2cedb 100644 --- a/src/server/biomes.c +++ b/src/server/biomes.c @@ -122,16 +122,6 @@ static bool find_near_vulcano(v2s32 pos, v2s32 *result) return false; } -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)); @@ -183,7 +173,7 @@ static void preprocess_row_ocean(v2s32 pos, unused f64 factor, void *row_data, v bool is_crater = vulcano_height > 0; if (! is_crater) - vulcano_height = min(vulcano_height + 5.0, 0.0); + vulcano_height = f64_min(vulcano_height + 5.0, 0.0); if (vulcano_height < 0) vulcano_height *= 2.0; @@ -202,7 +192,7 @@ static s32 height_ocean(unused v2s32 pos, f64 factor, f32 height, void *row_data OceanRowData *rdata = row_data; s32 ocean_floor = calculate_ocean_floor(factor, height); - return rdata->vulcano ? max(ocean_floor, rdata->vulcano_height) : ocean_floor; + return rdata->vulcano ? f64_max(ocean_floor, rdata->vulcano_height) : ocean_floor; } Node ocean_get_node_at(v3s32 pos, s32 diff, void *row_data) diff --git a/src/server/biomes.h b/src/server/biomes.h index 4615563..fb44049 100644 --- a/src/server/biomes.h +++ b/src/server/biomes.h @@ -1,9 +1,9 @@ #ifndef _BIOMES_H_ #define _BIOMES_H_ -#include #include "map.h" #include "perlin.h" +#include "types.h" typedef enum { diff --git a/src/server/database.c b/src/server/database.c index d205a88..afac7c8 100644 --- a/src/server/database.c +++ b/src/server/database.c @@ -37,13 +37,10 @@ static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action return NULL; } - size_t psize = sizeof(u32) * 3; - u32 *pos = malloc(psize); - pos[0] = htobe32(block->pos.x); - pos[1] = htobe32(block->pos.y); - pos[2] = htobe32(block->pos.z); + Blob buffer = {0, NULL}; + v3s32_write(&buffer, &block->pos); - sqlite3_bind_blob(stmt, 1, pos, psize, &free); + sqlite3_bind_blob(stmt, 1, buffer.data, buffer.siz, &free); return stmt; } @@ -51,12 +48,10 @@ static sqlite3_stmt *prepare_block_statement(MapBlock *block, const char *action // bind v3f64 to sqlite3 statement static inline void bind_v3f64(sqlite3_stmt *stmt, int idx, v3f64 pos) { - size_t psize = sizeof(f64) * 3; - f64 *blob = malloc(psize); - blob[0] = pos.x; - blob[1] = pos.y; - blob[2] = pos.z; - sqlite3_bind_blob(stmt, idx, blob, psize, &free); + Blob buffer = {0, NULL}; + v3f64_write(&buffer, &pos); + + sqlite3_bind_blob(stmt, idx, buffer.data, buffer.siz, &free); } // public functions @@ -72,7 +67,7 @@ void database_init() } const char *init_stmts[3]= { - "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, size INTEGER, rawsize INTEGER, data BLOB, mgsb_size INTEGER, mgsb_data BLOB);", + "CREATE TABLE IF NOT EXISTS map (pos BLOB PRIMARY KEY, generated INTEGER, data BLOB, mgsb BLOB);", "CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER);", "CREATE TABLE IF NOT EXISTS players (name TEXT PRIMARY KEY, pos BLOB);" }; @@ -115,7 +110,7 @@ bool database_load_block(MapBlock *block) { sqlite3_stmt *stmt; - if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, size, rawsize, data, mgsb_size, mgsb_data FROM map WHERE pos=?"))) + if (! (stmt = prepare_block_statement(block, "loading", "SELECT generated, data, mgsb FROM map WHERE pos=?"))) return false; int rc = sqlite3_step(stmt); @@ -125,18 +120,13 @@ bool database_load_block(MapBlock *block) MapBlockExtraData *extra = block->extra; extra->state = sqlite3_column_int(stmt, 0) ? MBS_READY : MBS_CREATED; - extra->size = sqlite3_column_int64(stmt, 1); - extra->rawsize = sqlite3_column_int64(stmt, 2); - extra->data = malloc(extra->size); - memcpy(extra->data, sqlite3_column_blob(stmt, 3), extra->size); - - MapgenStageBuffer decompressed_mgsb; - my_decompress(sqlite3_column_blob(stmt, 5), sqlite3_column_int64(stmt, 4), &decompressed_mgsb, sizeof(MapgenStageBuffer)); - - ITERATE_MAPBLOCK extra->mgs_buffer[x][y][z] = be32toh(decompressed_mgsb[x][y][z]); + Blob_read( &(Blob) {sqlite3_column_bytes(stmt, 1), (void *) sqlite3_column_blob(stmt, 1)}, &extra->data); + MapgenStageBuffer_read(&(Blob) {sqlite3_column_bytes(stmt, 2), (void *) sqlite3_column_blob(stmt, 2)}, &extra->mgsb); - if (! map_deserialize_block(block, extra->data, extra->size, extra->rawsize)) - printf("Error with deserializing block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z); + if (! map_deserialize_block(block, extra->data)) { + fprintf(stderr, "Failed to load block at (%d, %d, %d)\n", block->pos.x, block->pos.y, block->pos.z); + exit(EXIT_FAILURE); + } } else if (rc != SQLITE_DONE) { print_block_error(block, "loading"); } @@ -150,25 +140,20 @@ void database_save_block(MapBlock *block) { sqlite3_stmt *stmt; - if (! (stmt = prepare_block_statement(block, "saving", "REPLACE INTO map (pos, generated, size, rawsize, data, mgsb_size, mgsb_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)"))) + if (! (stmt = prepare_block_statement(block, "saving", "REPLACE INTO map (pos, generated, data, mgsb) VALUES(?1, ?2, ?3, ?4)"))) return; MapBlockExtraData *extra = block->extra; - MapgenStageBuffer uncompressed_mgsb; - ITERATE_MAPBLOCK uncompressed_mgsb[x][y][z] = htobe32(extra->mgs_buffer[x][y][z]); - - char *mgsb_data; - size_t mgsb_size; + Blob data = {0, NULL}; + Blob_write(&data, &extra->data); - my_compress(&uncompressed_mgsb, sizeof(MapgenStageBuffer), &mgsb_data, &mgsb_size); + Blob mgsb = {0, NULL}; + MapgenStageBuffer_write(&mgsb, &extra->mgsb); sqlite3_bind_int(stmt, 2, extra->state > MBS_CREATED); - sqlite3_bind_int64(stmt, 3, extra->size); - sqlite3_bind_int64(stmt, 4, extra->rawsize); - sqlite3_bind_blob(stmt, 5, extra->data, extra->size, SQLITE_TRANSIENT); - sqlite3_bind_int64(stmt, 6, mgsb_size); - sqlite3_bind_blob(stmt, 7, mgsb_data, mgsb_size, &free); + sqlite3_bind_blob(stmt, 3, data.data, data.siz, &free); + sqlite3_bind_blob(stmt, 4, mgsb.data, mgsb.siz, &free); if (sqlite3_step(stmt) != SQLITE_DONE) print_block_error(block, "saving"); @@ -234,12 +219,10 @@ bool database_load_player(char *name, v3f64 *pos_ptr) int rc = sqlite3_step(stmt); bool found = rc == SQLITE_ROW; - if (found) { - const f64 *pos = sqlite3_column_blob(stmt, 0); - *pos_ptr = (v3f64) {pos[0], pos[1], pos[2]}; - } else if (rc != SQLITE_DONE) { + if (found) + v3f64_read(&(Blob) {sqlite3_column_bytes(stmt, 0), (void *) sqlite3_column_blob(stmt, 0)}, pos_ptr); + else if (rc != SQLITE_DONE) fprintf(stderr, "Database error with loading player %s: %s\n", name, sqlite3_errmsg(database)); - } sqlite3_finalize(stmt); return found; diff --git a/src/server/mapgen.c b/src/server/mapgen.c index bfaaf0d..98da188 100644 --- a/src/server/mapgen.c +++ b/src/server/mapgen.c @@ -15,6 +15,7 @@ void mapgen_set_node(v3s32 pos, MapNode node, MapgenStage mgs, List *changed_blo .mgs = mgs, .changed_blocks = changed_blocks, }; + map_set_node(server_map.map, pos, node, true, &arg); } @@ -84,9 +85,9 @@ void mapgen_generate_block(MapBlock *block, List *changed_blocks) } pthread_mutex_lock(&block->mtx); - if (extra->mgs_buffer[x][y][z] <= MGS_TERRAIN) { - block->data[x][y][z] = map_node_create(node, NULL, 0); - extra->mgs_buffer[x][y][z] = MGS_TERRAIN; + if (extra->mgsb.raw.nodes[x][y][z] <= MGS_TERRAIN) { + block->data[x][y][z] = map_node_create(node, (Blob) {0, NULL}); + extra->mgsb.raw.nodes[x][y][z] = MGS_TERRAIN; } pthread_mutex_unlock(&block->mtx); } diff --git a/src/server/server.c b/src/server/server.c index d0e962c..a3587f2 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -1,193 +1,93 @@ #include #include -#include -#include -#include +#include #include "server/database.h" #include "server/server.h" #include "server/server_map.h" +#include "server/server_player.h" #include "signal_handlers.h" #include "util.h" -static Server server; +DragonnetListener *server; -// include handle_packets implementation - -#include "network.c" - -// utility functions - -// pthread start routine for reciever thread -static void *reciever_thread(void *arg) +static bool on_recv(DragonnetPeer *peer, DragonnetTypeId type, unused void *pkt) { - Client *client = arg; - - if (! handle_packets(client)) - server_disconnect_client(client, DISCO_NO_SEND | DISCO_NO_JOIN, "network error"); - - return NULL; + return ((ServerPlayer *) peer->extra)->auth != (type == DRAGONNET_TYPE_ToServerAuth); } -// accept a new connection, initialize client and start reciever thread -static void accept_client() +static void on_ToServerAuth(DragonnetPeer *peer, ToServerAuth *pkt) { - struct sockaddr_storage client_address = {0}; - socklen_t client_addrlen = sizeof(client_address); - - int fd = accept(server.sockfd, (struct sockaddr *) &client_address, &client_addrlen); - - if (fd == -1) { - if (errno != EINTR) - perror("accept"); - return; - } - - Client *client = malloc(sizeof(Client)); - client->fd = fd; - pthread_mutex_init(&client->mtx, NULL); - client->state = CS_CREATED; - client->address = address_string((struct sockaddr_in6 *) &client_address); - client->name = client->address; - client->server = &server; - client->pos = (v3f64) {0.0f, 0.0f, 0.0f}; - pthread_create(&client->net_thread, NULL, &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); + if (server_player_auth(peer->extra, pkt->name)) + pkt->name = NULL; } -// list_clear_func callback used on server shutdown to disconnect all clients properly -static void list_disconnect_client(void *key, unused void *value, unused void *arg) +// set a node on the map +static void on_ToServerSetnode(unused DragonnetPeer *peer, ToServerSetnode *pkt) { - server_disconnect_client(key, DISCO_NO_REMOVE | DISCO_NO_MESSAGE, ""); + map_set_node(server_map.map, pkt->pos, map_node_create(pkt->node, (Blob) {0, NULL}), false, NULL); } -// start up the server after socket was created, then accept connections until interrupted, then shutdown server -static void server_run(int fd) +// update player's position +static void on_ToServerPos(DragonnetPeer *peer, ToServerPos *pkt) { - server.sockfd = fd; - 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); - - database_init(); - server_map_init(&server); - server_map_prepare_spawn(); - - while (! interrupted) - accept_client(); - - printf("Shutting down\n"); - - pthread_rwlock_wrlock(&server.clients_rwlck); - list_clear_func(&server.clients, &list_disconnect_client, NULL); - 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); - - server_map_deinit(); - database_deinit(); + ServerPlayer *player = peer->extra; - exit(EXIT_SUCCESS); + pthread_rwlock_wrlock(&player->pos_lock); + player->pos = pkt->pos; + database_update_player_pos(player->name, player->pos); + pthread_rwlock_unlock(&player->pos_lock); } -// public functions - -// disconnect a client with various options an an optional detail message (flags: DiscoFlag bitmask) -void server_disconnect_client(Client *client, int flags, const char *detail) +// tell server map manager client requested the block +static void on_ToServerRequestBlock(DragonnetPeer *peer, ToServerRequestBlock *pkt) { - client->state = CS_DISCONNECTED; - - 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)); - - if (! (flags & DISCO_NO_SEND)) - send_command(client, CC_DISCONNECT); - - pthread_mutex_lock(&client->mtx); - close(client->fd); - pthread_mutex_unlock(&client->mtx); - - if (! (flags & DISCO_NO_JOIN)) - pthread_join(client->net_thread, NULL); - - if (client->name != client->address) - free(client->name); - free(client->address); - - pthread_mutex_destroy(&client->mtx); - free(client); + server_map_requested_block(peer->extra, pkt->pos); } // server entry point int main(int argc, char **argv) { - program_name = argv[0]; - - if (argc < 2) - internal_error("missing port"); - - struct addrinfo hints = { - .ai_family = AF_INET6, - .ai_socktype = SOCK_STREAM, - .ai_protocol = 0, - .ai_flags = AI_NUMERICSERV | AI_PASSIVE, - }; - - struct addrinfo *info = NULL; - - int gai_state = getaddrinfo(NULL, argv[1], &hints, &info); - - if (gai_state != 0) - internal_error(gai_strerror(gai_state)); + if (argc < 2) { + fprintf(stderr, "Missing address\n"); + return EXIT_FAILURE; + } - int fd = socket(info->ai_family, info->ai_socktype, 0); + if (! (server = dragonnet_listener_new(argv[1]))) { + fprintf(stderr, "Failed to listen to connections\n"); + return EXIT_FAILURE; + } - if (fd == -1) - syscall_error("socket"); + char *address = dragonnet_addr_str(server->laddr); + printf("Listening on %s\n", address); + free(address); - int flag = 1; + server->on_connect = &server_player_add; + 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_ToServerPos] = (void *) &on_ToServerPos; + server->on_recv_type[DRAGONNET_TYPE_ToServerRequestBlock] = (void *) &on_ToServerRequestBlock; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) - syscall_error("setsockopt"); + signal_handlers_init(); - if (bind(fd, info->ai_addr, info->ai_addrlen) == -1) - syscall_error("bind"); + server_player_init(); + database_init(); + server_map_init(); + server_map_prepare_spawn(); + dragonnet_listener_run(server); - if (listen(fd, 3) == -1) - syscall_error("listen"); + while (! interrupted) + sched_yield(); - char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr); - printf("Listening on %s\n", addrstr); - free(addrstr); + printf("Shutting down\n"); - freeaddrinfo(info); + dragonnet_listener_close(server); + server_map_deinit(); + database_deinit(); + server_player_deinit(); - signal_handlers_init(); - server_run(fd); + dragonnet_listener_delete(server); return EXIT_SUCCESS; } diff --git a/src/server/server.h b/src/server/server.h index 3a2ca84..c2adddb 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -1,43 +1,8 @@ #ifndef _SERVER_H_ #define _SERVER_H_ -#include -#include -#include -#include -#include "client/client_commands.h" -#include "server/server_commands.h" -#include "network.h" +#include -typedef struct -{ - int sockfd; // TCP socket to accept new connections - pthread_rwlock_t clients_rwlck; // lock to protect client list - List clients; // Client * -> NULL map with all connected clients - pthread_rwlock_t players_rwlck; // lock to protect player list - List players; // char * -> Client * map with clients that have finished auth -} Server; - -typedef struct Client -{ - int fd; // TCP socket for connection - pthread_mutex_t mtx; // mutex to protect socket - ClientState state; // state of the client (created, auth, active, disconnected) - char *address; // address string to use as identifier for log messages until auth is completed - char *name; // player name (must be unique) - Server *server; // pointer to server object (essentially the same for all clients) - pthread_t net_thread; // reciever thread ID - v3f64 pos; // player position -} Client; - -typedef enum -{ - DISCO_NO_REMOVE = 0x01, // don't remove from client and player list (to save extra work on server shutdown) - DISCO_NO_SEND = 0x02, // don't notfiy client about the disconnect (if client sent disconnect themselves or the TCP connection died) - DISCO_NO_MESSAGE = 0x04, // don't log a message about the disconnect (used on server shutdown) - DISCO_NO_JOIN = 0x08, // don't wait for the reciever thread to finish (if TCP connection death was reported by reciever thread, the thread is already dead) -} DiscoFlag; - -void server_disconnect_client(Client *client, int flags, const char *detail); // disconnect a client with various options an an optional detail message (flags: DiscoFlag bitmask) +DragonnetListener *server; #endif diff --git a/src/server/server_commands.c b/src/server/server_commands.c deleted file mode 100644 index 35e3784..0000000 --- a/src/server/server_commands.c +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include "day.h" -#include "server/database.h" -#include "server/server.h" -#include "server/server_config.h" -#include "server/server_map.h" -#include "perlin.h" -#include "util.h" - -// command callbacks - -// disconnect client without sending a packet (client won't recieve it) -static bool disconnect_handler(Client *client, bool good) -{ - if (good) - server_disconnect_client(client, DISCO_NO_SEND, NULL); - return true; -} - -// insert client into player list and update state (if checks pass) -static bool auth_handler(Client *client, bool good) -{ - char *name = read_string(client->fd, PLAYER_NAME_MAX); - - if (! name) - return false; - - if (! good) { - free(name); - return true; - } - - pthread_rwlock_wrlock(&client->server->players_rwlck); - u8 success = list_put(&client->server->players, name, client); - - if (success) { - client->name = name; - client->state = CS_ACTIVE; - - if (! database_load_player(client->name, &client->pos)) { - client->pos = (v3f64) {0.0, server_map.spawn_height + 0.5, 0.0}; - - database_create_player(client->name, client->pos); - } - } else { - free(name); - } - - pthread_mutex_lock(&client->mtx); - bool ret = write_u32(client->fd, CC_AUTH) && write_u8(client->fd, success); - if (ret && success) - ret = ret - && write_u32(client->fd, CC_INFO) && write_u32(client->fd, server_config.simulation_distance) && write_s32(client->fd, seed) - && write_u32(client->fd, CC_SETPOS) && write_v3f64(client->fd, client->pos) - && write_u32(client->fd, CC_TIMEOFDAY) && write_u64(client->fd, (u64) get_time_of_day()); - pthread_mutex_unlock(&client->mtx); - - pthread_rwlock_unlock(&client->server->players_rwlck); - - printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", client->address, name); - - return ret; -} - -// set a node on the map -static bool setnode_handler(Client *client, bool good) -{ - v3s32 pos; - - if (! read_v3s32(client->fd, &pos)) - return false; - - Node node; - - if (! read_u32(client->fd, &node)) - return false; - - if (good) - map_set_node(server_map.map, pos, map_node_create(node, NULL, 0), false, NULL); - - return true; -} - -// update player's position -static bool pos_handler(Client *client, bool good) -{ - v3f64 pos; - - if (! read_v3f64(client->fd, &pos)) - return false; - - if (good) { - client->pos = pos; - database_update_player_pos(client->name, client->pos); - } - - return true; -} - -// tell server map manager client requested the block -static bool request_block_handler(Client *client, bool good) -{ - v3s32 pos; - - if (! read_v3s32(client->fd, &pos)) - return false; - - if (good) - server_map_requested_block(client, pos); - - return true; -} - -// declared in network.h -CommandHandler command_handlers[SERVER_COMMAND_COUNT] = { - {0}, - {&disconnect_handler, "DISCONNECT", CS_CREATED | CS_ACTIVE}, - {&auth_handler, "AUTH", CS_CREATED}, - {&setnode_handler, "SETNODE", CS_ACTIVE}, - {&pos_handler, "POS", CS_ACTIVE}, - {&request_block_handler, "REQUEST_BLOCK", CS_ACTIVE}, -}; diff --git a/src/server/server_commands.h b/src/server/server_commands.h deleted file mode 100644 index 009a034..0000000 --- a/src/server/server_commands.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _SERVER_COMMANDS_H_ -#define _SERVER_COMMANDS_H_ - -// this file must be included after client.h or server.h and before network.h - -typedef enum -{ - SERVER_COMMAND_NULL, // invalid command - SC_DISCONNECT, // client notifies server about disconnecting - SC_AUTH, // client wants to authentify [body: name (zero terminated string)] - SC_SETNODE, // player placed a node [body: pos (v3s32), node (Node)] - SC_POS, // player moved [body: pos (v3f)] - SC_REQUEST_BLOCK, // request to send a block [body: pos (v3s32)] - SERVER_COMMAND_COUNT, // count of available commands -} ServerCommand; - -#ifdef _CLIENT_H_ -typedef ServerCommand RemoteCommand; -#endif - -#ifdef _SERVER_H_ -typedef ServerCommand HostCommand; -#define HOST_COMMAND_COUNT SERVER_COMMAND_COUNT -#endif - -#endif diff --git a/src/server/server_map.c b/src/server/server_map.c index ae7e76e..68bd9ec 100644 --- a/src/server/server_map.c +++ b/src/server/server_map.c @@ -11,23 +11,31 @@ #include "util.h" struct ServerMap server_map; -static Server *server; // utility functions +// return true if a player is close enough to a block to access it +static bool within_simulation_distance(ServerPlayer *player, v3s32 blkp, u32 dist) +{ + pthread_rwlock_rdlock(&player->pos_lock); + v3s32 ppos = map_node_to_block_pos((v3s32) {player->pos.x, player->pos.y, player->pos.z}, NULL); + pthread_rwlock_unlock(&player->pos_lock); + + return abs(ppos.x - blkp.x) <= (s32) dist + && abs(ppos.y - blkp.y) <= (s32) dist + && abs(ppos.z - blkp.z) <= (s32) dist; +} + // send a block to a client and reset block request -static void send_block(Client *client, MapBlock *block) +static void send_block(ServerPlayer *player, MapBlock *block) { - MapBlockExtraData *extra = block->extra; + if (! within_simulation_distance(player, block->pos, server_config.simulation_distance)) + return; - pthread_mutex_lock(&client->mtx); - if (client->state == CS_ACTIVE) - (void) (write_u32(client->fd, CC_BLOCK) - && write_v3s32(client->fd, block->pos) - && write_u64(client->fd, extra->size) - && write_u64(client->fd, extra->rawsize) - && write(client->fd, extra->data, extra->size) != -1); - pthread_mutex_unlock(&client->mtx); + dragonnet_peer_send_ToClientBlock(player->peer, &(ToClientBlock) { + .pos = block->pos, + .data = ((MapBlockExtraData *) block->extra)->data, + }); } // send block to near clients @@ -39,23 +47,15 @@ static void send_block_to_near(MapBlock *block) if (extra->state == MBS_GENERATING) return; - if (extra->data) - free(extra->data); + Blob_free(&extra->data); + extra->data = map_serialize_block(block); - map_serialize_block(block, &extra->data, &extra->size, &extra->rawsize); database_save_block(block); if (extra->state == MBS_CREATED) return; - pthread_rwlock_rdlock(&server->players_rwlck); - ITERATE_LIST(&server->players, pair) { - Client *client = pair->value; - - if (within_simulation_distance(client->pos, block->pos, server_config.simulation_distance)) - send_block(client, block); - } - pthread_rwlock_unlock(&server->players_rwlck); + server_player_iterate((void *) &send_block, block); } // list_clear_func callback for sending changed blocks to near clients @@ -128,11 +128,11 @@ static void on_create_block(MapBlock *block) if (! database_load_block(block)) { extra->state = MBS_CREATED; - extra->data = NULL; + extra->data = (Blob) {0, NULL}; ITERATE_MAPBLOCK { - block->data[x][y][z] = map_node_create(NODE_AIR, NULL, 0); - extra->mgs_buffer[x][y][z] = MGS_VOID; + block->data[x][y][z] = map_node_create(NODE_AIR, (Blob) {0, NULL}); + extra->mgsb.raw.nodes[x][y][z] = MGS_VOID; } } } @@ -143,9 +143,7 @@ static void on_delete_block(MapBlock *block) { MapBlockExtraData *extra = block->extra; - if (extra->data) - free(extra->data); - + Blob_free(&extra->data); free(extra); } @@ -174,7 +172,7 @@ static bool on_set_node(MapBlock *block, v3u8 offset, unused MapNode *node, void else mgs = MGS_PLAYER; - MapgenStage *old_mgs = &((MapBlockExtraData *) block->extra)->mgs_buffer[offset.x][offset.y][offset.z]; + MapgenStage *old_mgs = &((MapBlockExtraData *) block->extra)->mgsb.raw.nodes[offset.x][offset.y][offset.z]; if (mgs >= *old_mgs) { *old_mgs = mgs; @@ -215,35 +213,37 @@ static void join_mapgen_threads() // generate a hut for new players to spawn in static void generate_spawn_hut() { - f32 wood_color[3] = {0.11f, 1.0f, 0.29f}; + Blob wood_color = {0, NULL}; + HSLData_write(&wood_color, &(HSLData) {{0.11f, 1.0f, 0.29f}}); + List changed_blocks = list_create(NULL); for (s32 x = -4; x <= +4; x++) { for (s32 y = 0; y <= 3; y++) { for (s32 z = -3; z <= +2; z++) { - mapgen_set_node((v3s32) {x, server_map.spawn_height + y, z}, map_node_create(NODE_AIR, NULL, 0), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {x, server_map.spawn_height + y, z}, map_node_create(NODE_AIR, (Blob) {0, NULL}), MGS_PLAYER, &changed_blocks); } } } for (s32 x = -5; x <= +5; x++) { for (s32 z = -4; z <= +3; z++) { - mapgen_set_node((v3s32) {x, server_map.spawn_height - 1, z}, map_node_create(NODE_OAK_WOOD, wood_color, sizeof wood_color), MGS_PLAYER, &changed_blocks); - mapgen_set_node((v3s32) {x, server_map.spawn_height + 4, z}, map_node_create(NODE_OAK_WOOD, wood_color, sizeof wood_color), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {x, server_map.spawn_height - 1, z}, map_node_create(NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {x, server_map.spawn_height + 4, z}, map_node_create(NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); } } for (s32 y = 0; y <= 3; y++) { for (s32 x = -5; x <= +5; x++) { - mapgen_set_node((v3s32) {x, server_map.spawn_height + y, -4}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -1) || (x >= +1 && x <= +2))) ? NODE_AIR : NODE_OAK_WOOD, wood_color, sizeof(f32) * 3), MGS_PLAYER, &changed_blocks); - mapgen_set_node((v3s32) {x, server_map.spawn_height + y, +3}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -2) || (x >= +1 && x <= +3))) ? NODE_AIR : NODE_OAK_WOOD, wood_color, sizeof(f32) * 3), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {x, server_map.spawn_height + y, -4}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -1) || (x >= +1 && x <= +2))) ? NODE_AIR : NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {x, server_map.spawn_height + y, +3}, map_node_create(((y == 1 || y == 2) && ((x >= -3 && x <= -2) || (x >= +1 && x <= +3))) ? NODE_AIR : NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); } } for (s32 y = 0; y <= 3; y++) { for (s32 z = -3; z <= +2; z++) { - mapgen_set_node((v3s32) {-5, server_map.spawn_height + y, z}, map_node_create(NODE_OAK_WOOD, wood_color, sizeof(f32) * 3), MGS_PLAYER, &changed_blocks); - mapgen_set_node((v3s32) {+5, server_map.spawn_height + y, z}, map_node_create(((y != 3) && (z == -1 || z == +0)) ? NODE_AIR : NODE_OAK_WOOD, wood_color, sizeof(f32) * 3), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {-5, server_map.spawn_height + y, z}, map_node_create(NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); + mapgen_set_node((v3s32) {+5, server_map.spawn_height + y, z}, map_node_create(((y != 3) && (z == -1 || z == +0)) ? NODE_AIR : NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); } } @@ -271,7 +271,7 @@ static void generate_spawn_hut() if (node_definitions[node].solid) break; - mapgen_set_node(pos, map_node_create(node == NODE_LAVA ? NODE_VULCANO_STONE : NODE_OAK_WOOD, wood_color, sizeof(f32) * 3), MGS_PLAYER, &changed_blocks); + mapgen_set_node(pos, map_node_create(node == NODE_LAVA ? NODE_VULCANO_STONE : NODE_OAK_WOOD, wood_color), MGS_PLAYER, &changed_blocks); } } @@ -281,10 +281,8 @@ static void generate_spawn_hut() // public functions // ServerMap singleton constructor -void server_map_init(Server *srv) +void server_map_init() { - server = srv; - server_map.map = map_create((MapCallbacks) { .create_block = &on_create_block, .delete_block = &on_delete_block, @@ -308,9 +306,9 @@ void server_map_deinit() } // handle block request from client (thread safe) -void server_map_requested_block(Client *client, v3s32 pos) +void server_map_requested_block(ServerPlayer *player, v3s32 pos) { - if (within_simulation_distance(client->pos, pos, server_config.simulation_distance)) { + if (within_simulation_distance(player, pos, server_config.simulation_distance)) { MapBlock *block = map_get_block(server_map.map, pos, true); pthread_mutex_lock(&block->mtx); @@ -325,7 +323,7 @@ void server_map_requested_block(Client *client, v3s32 pos) break; case MBS_READY: - send_block(client, block); + send_block(player, block); }; pthread_mutex_unlock(&block->mtx); } diff --git a/src/server/server_map.h b/src/server/server_map.h index 9e3a7f3..da7c2d4 100644 --- a/src/server/server_map.h +++ b/src/server/server_map.h @@ -4,7 +4,8 @@ #include #include #include "map.h" -#include "server/server.h" +#include "server/server_player.h" +#include "types.h" typedef enum { @@ -22,8 +23,6 @@ typedef enum MGS_PLAYER, // player-placed nodes or things placed after map generation } MapgenStage; -typedef MapgenStage MapgenStageBuffer[MAPBLOCK_SIZE][MAPBLOCK_SIZE][MAPBLOCK_SIZE]; - typedef struct { MapgenStage mgs; List *changed_blocks; @@ -31,12 +30,10 @@ typedef struct { typedef struct { - char *data; // cached serialized data - size_t size; // size of data - size_t rawsize; // size of decompressed data + Blob data; // the big cum MapBlockState state; // generation state of the block pthread_t mapgen_thread; // thread that is generating block - MapgenStageBuffer mgs_buffer; // buffer to make sure mapgen only overrides things it should + MapgenStageBuffer mgsb; // buffer to make sure mapgen only overrides things it should } MapBlockExtraData; extern struct ServerMap { @@ -48,9 +45,9 @@ extern struct ServerMap { s32 spawn_height; // height to spawn players at } server_map; // ServerMap singleton -void server_map_init(Server *server); // ServerMap singleton constructor -void server_map_deinit(); // ServerMap singleton destructor -void server_map_requested_block(Client *client, v3s32 pos); // handle block request from client (thread safe) -void server_map_prepare_spawn(); // prepare spawn region +void server_map_init(); // ServerMap singleton constructor +void server_map_deinit(); // ServerMap singleton destructor +void server_map_requested_block(ServerPlayer *player, v3s32 pos); // handle block request from client (thread safe) +void server_map_prepare_spawn(); // prepare spawn region #endif diff --git a/src/server/server_player.c b/src/server/server_player.c new file mode 100644 index 0000000..e480196 --- /dev/null +++ b/src/server/server_player.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include "server/database.h" +#include "server/server_config.h" +#include "server/server_map.h" +#include "server/server_player.h" +#include "perlin.h" +#include "day.h" +#include "util.h" + +static bool shutting_down = false; +static pthread_rwlock_t shutting_down_lock; + +static List players; +static pthread_rwlock_t players_lock; + +static List names; +static pthread_rwlock_t names_lock; + +static u64 next_id = 1; + +static bool list_compare_u64(u64 *p1, u64 *p2) +{ + return *p1 == *p2; +} + +static bool get_lock(pthread_rwlock_t *lock, bool write) +{ + pthread_rwlock_rdlock(&shutting_down_lock); + if (shutting_down) { + pthread_rwlock_unlock(&shutting_down_lock); + return false; + } + + if (write) + pthread_rwlock_wrlock(lock); + else + pthread_rwlock_rdlock(lock); + + pthread_rwlock_unlock(&shutting_down_lock); + return true; +} + +void server_player_init() +{ + pthread_rwlock_init(&shutting_down_lock, NULL); + + players = list_create((void *) &list_compare_u64); + pthread_rwlock_init(&players_lock, NULL); + + names = list_create(&list_compare_string); + pthread_rwlock_init(&names_lock, NULL); +} + +// list_clear_func callback used on server shutdown to disconnect all clients properly +static void list_disconnect_player(void *key, unused void *value, unused void *arg) +{ + ServerPlayer *player = key; + + pthread_t recv_thread = player->peer->recv_thread; + server_player_disconnect(player); + pthread_join(recv_thread, NULL); +} + +void server_player_deinit() +{ + pthread_rwlock_wrlock(&shutting_down_lock); + shutting_down = true; + + pthread_rwlock_wrlock(&players_lock); + pthread_rwlock_wrlock(&names_lock); + pthread_rwlock_unlock(&shutting_down_lock); + + list_clear_func(&players, &list_disconnect_player, NULL); + list_clear(&names); + + pthread_rwlock_destroy(&players_lock); + pthread_rwlock_destroy(&names_lock); + pthread_rwlock_destroy(&shutting_down_lock); +} + +void server_player_add(DragonnetPeer *peer) +{ + ServerPlayer *player = malloc(sizeof *player); + + player->id = next_id++; + player->peer = peer; + pthread_rwlock_init(&player->ref, NULL); + player->auth = false; + player->name = dragonnet_addr_str(peer->raddr); + pthread_rwlock_init(&player->auth_lock, NULL); + player->pos = (v3f64) {0.0f, 0.0f, 0.0f}; + pthread_rwlock_init(&player->pos_lock, NULL); + + printf("Connected %s\n", player->name); + + // accept thread is joined before shutdown, we are guaranteed to obtain the lock + pthread_rwlock_wrlock(&players_lock); + + list_put(&players, &player->id, player); + peer->extra = player; + + pthread_rwlock_unlock(&players_lock); +} + +void server_player_remove(DragonnetPeer *peer) +{ + ServerPlayer *player = peer->extra; + + // only (this) recv thread will modify the auth or name fields, no rdlocks needed + + if (get_lock(&players_lock, true)) { + list_delete(&players, &player->id); + pthread_rwlock_unlock(&players_lock); + + printf("Disconnected %s\n", player->name); + } + + if (player->auth && get_lock(&names_lock, true)) { + list_delete(&names, player->name); + pthread_rwlock_unlock(&names_lock); + } + + pthread_rwlock_wrlock(&player->ref); + + free(player->name); + + pthread_rwlock_destroy(&player->ref); + pthread_rwlock_destroy(&player->auth_lock); + pthread_rwlock_destroy(&player->pos_lock); + + free(player); +} + +u64 server_player_find(char *name) +{ + if (! get_lock(&names_lock, false)) + return 0; + + u64 *id = list_get(&names, name); + return id ? *id : 0; +} + +ServerPlayer *server_player_grab(u64 id) +{ + if (! id) + return NULL; + + if (! get_lock(&players_lock, false)) + return NULL; + + ServerPlayer *player = list_get(&players, &id); + if (player) + pthread_rwlock_rdlock(&player->ref); + + pthread_rwlock_unlock(&players_lock); + + return player; +} + +void server_player_drop(ServerPlayer *player) +{ + pthread_rwlock_unlock(&player->ref); +} + +bool server_player_auth(ServerPlayer *player, char *name) +{ + if (! get_lock(&names_lock, true)) + return false; + + pthread_rwlock_wrlock(&player->auth_lock); + pthread_rwlock_wrlock(&player->pos_lock); + + bool success = list_put(&names, name, &player->id); + + dragonnet_peer_send_ToClientAuth(player->peer, &(ToClientAuth) { + .success = success, + }); + + if (success) { + printf("Authentication %s: %s -> %s\n", success ? "success" : "failure", player->name, name); + + free(player->name); + player->name = name; + player->auth = true; + + if (! database_load_player(player->name, &player->pos)) { + player->pos = (v3f64) {0.0, server_map.spawn_height + 0.5, 0.0}; + database_create_player(player->name, player->pos); + } + + dragonnet_peer_send_ToClientInfo(player->peer, &(ToClientInfo) { + .seed = seed, + .simulation_distance = server_config.simulation_distance, + }); + + dragonnet_peer_send_ToClientTimeOfDay(player->peer, &(ToClientTimeOfDay) { + .time_of_day = get_time_of_day(), + }); + + server_player_send_pos(player); + } + + pthread_rwlock_unlock(&player->pos_lock); + pthread_rwlock_unlock(&player->auth_lock); + pthread_rwlock_unlock(&names_lock); + + return success; +} + +void server_player_disconnect(ServerPlayer *player) +{ + dragonnet_peer_shutdown(player->peer); +} + +void server_player_send_pos(ServerPlayer *player) +{ + dragonnet_peer_send_ToClientPos(player->peer, & (ToClientPos) { + .pos = player->pos, + }); +} + +void server_player_iterate(void (cb)(ServerPlayer *, void *), void *arg) +{ + if (! get_lock(&players_lock, false)) + return; + + ITERATE_LIST(&players, pair) { + ServerPlayer *player = pair->value; + + pthread_rwlock_rdlock(&player->auth_lock); + if (player->auth) + cb(player, arg); + pthread_rwlock_unlock(&player->auth_lock); + } + + pthread_rwlock_unlock(&players_lock); +} + +/* +229779 +373875 +374193 +110738 +390402 +357272 +390480 + +(these are only the wholesome ones) +*/ diff --git a/src/server/server_player.h b/src/server/server_player.h new file mode 100644 index 0000000..ad035fc --- /dev/null +++ b/src/server/server_player.h @@ -0,0 +1,39 @@ +#ifndef _SERVER_PLAYER_H_ +#define _SERVER_PLAYER_H_ + +#include +#include +#include +#include "types.h" + +typedef struct +{ + u64 id; // unique identifier + DragonnetPeer *peer; + pthread_rwlock_t ref; // programming socks make you 100% cuter + + bool auth; + char *name; // player name + pthread_rwlock_t auth_lock; // why + + v3f64 pos; // player position + pthread_rwlock_t pos_lock; // i want to commit die +} ServerPlayer; + +void server_player_init(); +void server_player_deinit(); + +void server_player_add(DragonnetPeer *peer); +void server_player_remove(DragonnetPeer *peer); + +u64 server_player_find(char *name); + +ServerPlayer *server_player_grab(u64 id); +void server_player_drop(ServerPlayer *player); + +bool server_player_auth(ServerPlayer *player, char *name); +void server_player_disconnect(ServerPlayer *player); +void server_player_send_pos(ServerPlayer *player); +void server_player_iterate(void (cb)(ServerPlayer *, void *), void *arg); + +#endif diff --git a/src/server/trees.c b/src/server/trees.c index 5d4fa5e..31dc6c7 100644 --- a/src/server/trees.c +++ b/src/server/trees.c @@ -130,9 +130,9 @@ static void pine_tree(v3s32 pos, List *changed_blocks) s32 dir = (noise3d(tree_pos.x, tree_pos.y, tree_pos.z, 0, seed + SO_PINETREE_BRANCH_DIR) * 0.5 + 0.5) * 4.0; for (v3s32 branch_pos = tree_pos; branch_length > 0; branch_length--, branch_pos = v3s32_add(branch_pos, dirs[dir])) - mapgen_set_node(branch_pos, map_node_create(NODE_PINE_WOOD, NULL, 0), MGS_TREES, changed_blocks); + mapgen_set_node(branch_pos, map_node_create(NODE_PINE_WOOD, (Blob) {0, NULL}), MGS_TREES, changed_blocks); - mapgen_set_node(tree_pos, map_node_create(NODE_PINE_WOOD, NULL, 0), MGS_TREES, changed_blocks); + mapgen_set_node(tree_pos, map_node_create(NODE_PINE_WOOD, (Blob) {0, NULL}), MGS_TREES, changed_blocks); } } diff --git a/src/server/trees.h b/src/server/trees.h index 439d37e..3bc6763 100644 --- a/src/server/trees.h +++ b/src/server/trees.h @@ -1,9 +1,9 @@ #ifndef _TREES_H_ #define _TREES_H_ -#include -#include +#include #include "perlin.h" +#include "types.h" #define NUM_TREES 3 diff --git a/src/server/voxelctx.c b/src/server/voxelctx.c index 5023f09..6f5ee20 100644 --- a/src/server/voxelctx.c +++ b/src/server/voxelctx.c @@ -5,8 +5,6 @@ #include "perlin.h" #include "util.h" -#define CREATE_NODE map_node_create(node, use_color ? (f32[]) {VOXELCTXSTATE(ctx).h / 360.0, VOXELCTXSTATE(ctx).s, VOXELCTXSTATE(ctx).l} : NULL, use_color ? sizeof(f32) * 3 : 0) - static VoxelctxState *create_state(VoxelctxState *old) { VoxelctxState *state = malloc(sizeof(VoxelctxState)); @@ -229,7 +227,21 @@ void voxelctx_cube(Voxelctx *ctx, Node node, bool use_color) v[i] = floor(VOXELCTXSTATE(ctx).pos[i] + f + 0.5f); } - mapgen_set_node(v3s32_add(ctx->pos, (v3s32) {v[0], v[2], v[1]}), CREATE_NODE, ctx->mgs, ctx->changed_blocks); + Blob buffer = {0, NULL}; + + if (use_color) + HSLData_write(&buffer, &(HSLData) {{ + VOXELCTXSTATE(ctx).h / 360.0, + VOXELCTXSTATE(ctx).s, + VOXELCTXSTATE(ctx).l, + }}); + + mapgen_set_node( + v3s32_add(ctx->pos, (v3s32) {v[0], v[2], v[1]}), + map_node_create(node, buffer), + ctx->mgs, + ctx->changed_blocks + ); } } diff --git a/src/server/voxelctx.h b/src/server/voxelctx.h index a3f3115..42618b3 100644 --- a/src/server/voxelctx.h +++ b/src/server/voxelctx.h @@ -4,8 +4,8 @@ #define VOXELCTXSTATE(ctx) (*((VoxelctxState *) (ctx)->statestack.first->key)) #include -#include -#include +#include +#include "types.h" #include "server/server_map.h" typedef struct diff --git a/src/types.def b/src/types.def new file mode 100644 index 0000000..4a82d9c --- /dev/null +++ b/src/types.def @@ -0,0 +1,50 @@ +#define MAPBLOCK_SIZE 16 + +HSLData + v3f32 color + +SerializedMapNode + u32 type + Blob data + +SerializedMapBlockRaw + SerializedMapNode[MAPBLOCK_SIZE][MAPBLOCK_SIZE][MAPBLOCK_SIZE] nodes + +SerializedMapBlock + compressed SerializedMapBlockRaw raw + +MapgenStageBufferRaw + u32[MAPBLOCK_SIZE][MAPBLOCK_SIZE][MAPBLOCK_SIZE] nodes + +MapgenStageBuffer + compressed MapgenStageBufferRaw raw + +pkt ToServerAuth + String name + +pkt ToServerSetnode + v3s32 pos + u32 node + +pkt ToServerPos + v3f64 pos + +pkt ToServerRequestBlock + v3s32 pos + +pkt ToClientAuth + u8 success + +pkt ToClientBlock + v3s32 pos + Blob data + +pkt ToClientInfo + u32 simulation_distance + s32 seed + +pkt ToClientPos + v3f64 pos + +pkt ToClientTimeOfDay + u64 time_of_day diff --git a/src/util.c b/src/util.c index 3836e02..436e4d9 100644 --- a/src/util.c +++ b/src/util.c @@ -1,117 +1,5 @@ -#include -#include -#include -#include -#include +#include #include -#include "map.h" -#include "util.h" - -const char *program_name; - -// print system call related error message and exit -void syscall_error(const char *err) -{ - perror(err); - exit(EXIT_FAILURE); -} - -// print general error message and exit -void internal_error(const char *err) -{ - fprintf(stderr, "%s: %s\n", program_name, err); - exit(EXIT_FAILURE); -} - -// read from fd until \0 or EOF terminator -// store result including terminator into allocated buffer until bufsiz+1 is hit, return NULL on read error -char *read_string(int fd, size_t bufsiz) -{ - char buf[bufsiz + 1]; - buf[bufsiz] = 0; - for (size_t i = 0;; i++) { - char c; - if (read(fd, &c, 1) == -1) { - perror("read"); - return NULL; - } - if (i < bufsiz) - buf[i] = c; - if (c == EOF || c == 0) - break; - } - return strdup(buf); -} - -// convert IPv6 address to human readable, return allocated buffer -char *address_string(struct sockaddr_in6 *addr) -{ - char address[INET6_ADDRSTRLEN] = {0}; - char port[6] = {0}; - - if (inet_ntop(addr->sin6_family, &addr->sin6_addr, address, INET6_ADDRSTRLEN) == NULL) - perror("inet_ntop"); - sprintf(port, "%d", ntohs(addr->sin6_port)); - - char *result = malloc(strlen(address) + 1 + strlen(port) + 1); - sprintf(result, "%s:%s", address, port); - return result; -} - -// compress data using ZLib and store result(buffer allocated by malloc) in compressed -void my_compress(const void *uncompressed, size_t uncompressed_size, char **compressed, size_t *compressed_size) -{ - char compressed_buffer[uncompressed_size]; - - z_stream stream; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - stream.avail_in = stream.avail_out = uncompressed_size; - stream.next_in = (Bytef *) uncompressed; - stream.next_out = (Bytef *) compressed_buffer; - - deflateInit(&stream, Z_BEST_COMPRESSION); - deflate(&stream, Z_FINISH); - deflateEnd(&stream); - - *compressed_size = stream.total_out; - *compressed = malloc(*compressed_size); - memcpy(*compressed, compressed_buffer, *compressed_size); -} - -// decompress data and put result into decompressed, return false if decompressed size does not match expected_decompressed_size -bool my_decompress(const char *compressed, size_t compressed_size, void *decompressed, size_t expected_decompressed_size) -{ - z_stream stream; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - stream.avail_in = compressed_size; - stream.next_in = (Bytef *) compressed; - stream.avail_out = expected_decompressed_size; - stream.next_out = (Bytef *) decompressed; - - inflateInit(&stream); - inflate(&stream, Z_NO_FLUSH); - inflateEnd(&stream); - - return (size_t) stream.total_out == expected_decompressed_size; -} - -// return true if a player is close enough to a block to access it -bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulation_distance) -{ - v3s32 player_block_pos = map_node_to_block_pos((v3s32) {player_pos.x, player_pos.y, player_pos.z}, NULL); - return abs(player_block_pos.x - block_pos.x) <= (s32) simulation_distance && abs(player_block_pos.y - block_pos.y) <= (s32) simulation_distance && abs(player_block_pos.z - block_pos.z) <= (s32) simulation_distance; -} - -f64 clamp(f64 v, f64 min, f64 max) -{ - return v < min ? min : v > max ? max : v; -} char *format_string(const char *format, ...) { @@ -122,32 +10,3 @@ char *format_string(const char *format, ...) va_end(args); return ptr; } - -void *buffer_read(unsigned char **buffer, size_t *bufsiz, size_t size) -{ - if (size == 0) - return NULL; - - if (*bufsiz < size) - return NULL; - - void *old_buffer = *buffer; - - *bufsiz -= size; - *buffer += size; - - return old_buffer; -} - -void buffer_write(unsigned char **buffer, size_t *bufsiz, void *data, size_t size) -{ - if (size == 0) - return; - - size_t old_bufsiz = *bufsiz; - - *bufsiz += size; - *buffer = realloc(*buffer, *bufsiz); - - memcpy(*buffer + old_bufsiz, data, size); -} diff --git a/src/util.h b/src/util.h index 8d7099e..f8b0459 100644 --- a/src/util.h +++ b/src/util.h @@ -1,18 +1,6 @@ #ifndef _UTIL_H_ #define _UTIL_H_ -#include -#ifdef WIN32 -#include -#include -#else -#include -#include -#include -#include -#endif -#include - #define ever (;;) // infinite for loop with style #define INBRACES(str) (str) ? "(" : "", (str) ? (str) : "", (str) ? ")" : "" // wrapper for printf to optionally add a message in braces if message is not NULL #define CMPBOUNDS(x) ((x) == 0 ? 0 : (x) > 0 ? 1 : -1) // resolves to 1 if x > 0, 0 if x == 0 and -1 if x < 0 @@ -20,18 +8,6 @@ #define unused __attribute__ ((unused)) #define U32(x) (((u32) 1 << 31) + (x)) -extern const char *program_name; // this has to be set to program name on startup - -void syscall_error(const char *err); // print system call related error message and exit -void internal_error(const char *err); // print general error message and exit -char *read_string(int fd, size_t bufsiz); // read from fd until \0 or EOF terminator -char *address_string(struct sockaddr_in6 *addr); // convert IPv6 address to human readable, return allocated buffer -void my_compress(const void *uncompressed, size_t uncompressed_size, char **compressed, size_t *compressed_size); // compress data using ZLib and store result(buffer allocated by malloc) in compressed -bool my_decompress(const char *compressed, size_t compressed_size, void *decompressed, size_t expected_decompressed_size); // decompress data and put result into decompressed, return false if decompressed size does not match expected_decompressed_size -bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulation_distance); // return true if a player is close enough to a block to access it -f64 clamp(f64 v, f64 min, f64 max); char *format_string(const char *format, ...); -void *buffer_read(unsigned char **buffer, size_t *bufsiz, size_t size); -void buffer_write(unsigned char **buffer, size_t *bufsiz, void *data, size_t size); #endif -- 2.44.0