Use dragonnet
parent
d8982996ab
commit
7edcc13168
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b2fd5e955c0f910fdd1abf89626cfe324efbfe90
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 39b52e8cfa889d55008f2edd0933d6b421556c34
|
|
@ -1 +1 @@
|
|||
Subproject commit b3c245ba9b111462f2fff6178b08b486cd553f1b
|
||||
Subproject commit 61292ea8a973ba03f93ebf4acde705071e15ccaf
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 97d2850af13c339369093b78abe5265845d78220
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
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"
|
||||
"${DEPS_DIR}/dragonport/asprintf.c"
|
||||
"${DEPS_DIR}/perlin/perlin.c"
|
||||
)
|
||||
# Common sources
|
||||
|
||||
set(COMMON_SOURCES
|
||||
${DEPS_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"
|
||||
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)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
extern struct Camera
|
||||
{
|
||||
|
|
|
@ -2,159 +2,111 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#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);
|
||||
while (client_auth.state == AUTH_INIT)
|
||||
;
|
||||
|
||||
client.state = CS_DISCONNECTED;
|
||||
printf("Disconnected %s%s%s\n", INBRACES(detail));
|
||||
close(client.fd);
|
||||
return (client_auth.state == AUTH_WAIT) == (type == DRAGONNET_TYPE_ToClientAuth);
|
||||
}
|
||||
|
||||
static void on_disconnect(unused DragonnetPeer *peer)
|
||||
{
|
||||
interrupted = true;
|
||||
while (! finished)
|
||||
;
|
||||
}
|
||||
|
||||
static void on_ToClientAuth(unused DragonnetPeer *peer, ToClientAuth *pkt)
|
||||
{
|
||||
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");
|
||||
}
|
||||
pthread_mutex_unlock(&client.mtx);
|
||||
}
|
||||
|
||||
void client_send_position(v3f64 pos)
|
||||
static void on_ToClientBlock(unused DragonnetPeer *peer, ToClientBlock *pkt)
|
||||
{
|
||||
pthread_mutex_lock(&client.mtx);
|
||||
(void) (write_u32(client.fd, SC_POS) && write_v3f64(client.fd, pos));
|
||||
pthread_mutex_unlock(&client.mtx);
|
||||
MapBlock *block = map_get_block(client_map.map, pkt->pos, true);
|
||||
|
||||
map_deserialize_block(block, pkt->data);
|
||||
client_map_block_received(block);
|
||||
}
|
||||
|
||||
#include "network.c"
|
||||
|
||||
static void *reciever_thread(unused void *arg)
|
||||
static void on_ToClientInfo(unused DragonnetPeer *peer, ToClientInfo *pkt)
|
||||
{
|
||||
handle_packets(&client);
|
||||
|
||||
if (errno != EINTR)
|
||||
client_disconnect(false, "network error");
|
||||
|
||||
return NULL;
|
||||
client_map_set_simulation_distance(pkt->simulation_distance);
|
||||
seed = pkt->seed;
|
||||
}
|
||||
|
||||
static bool client_name_prompt()
|
||||
static void on_ToClientPos(unused DragonnetPeer *peer, ToClientPos *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_player_set_position(pkt->pos);
|
||||
}
|
||||
|
||||
static bool client_authenticate()
|
||||
static void on_ToClientTimeOfDay(unused DragonnetPeer *peer, ToClientTimeOfDay *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;
|
||||
}
|
||||
|
||||
static bool client_start(int fd)
|
||||
{
|
||||
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 < 2) {
|
||||
fprintf(stderr, "Missing address\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 3)
|
||||
internal_error("missing address or port");
|
||||
if (! (client = dragonnet_connect(argv[1]))) {
|
||||
fprintf(stderr, "Failed to connect to server\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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 (gai_state != 0)
|
||||
internal_error(gai_strerror(gai_state));
|
||||
|
||||
int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
||||
|
||||
if (fd == -1)
|
||||
syscall_error("socket");
|
||||
|
||||
if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
|
||||
syscall_error("connect");
|
||||
|
||||
char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
|
||||
printf("Connected to %s\n", addrstr);
|
||||
free(addrstr);
|
||||
|
||||
freeaddrinfo(info);
|
||||
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;
|
||||
|
||||
signal_handlers_init();
|
||||
client_map_init();
|
||||
client_player_init();
|
||||
dragonnet_peer_run(client);
|
||||
|
||||
return client_start(fd) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
if (! client_auth_init())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (! game())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
dragonnet_peer_shutdown(client);
|
||||
client_auth_deinit();
|
||||
client_player_deinit();
|
||||
client_map_deinit();
|
||||
|
||||
pthread_t recv_thread = client->recv_thread;
|
||||
finished = true;
|
||||
pthread_join(recv_thread, NULL);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,8 @@
|
|||
#ifndef _CLIENT_H_
|
||||
#define _CLIENT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "client/client_commands.h"
|
||||
#include "client/scene.h"
|
||||
#include "server/server_commands.h"
|
||||
#include "network.h"
|
||||
#include <dragonnet/peer.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <linenoise/linenoise.h>
|
||||
#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);
|
||||
}
|
|
@ -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
|
|
@ -1,129 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <dragontype/number.h>
|
||||
#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},
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <dragontype/queue.h>
|
||||
#include <dragonstd/queue.h>
|
||||
#include "map.h"
|
||||
#include "client/object.h"
|
||||
#define NUM_MESHGEN_THREADS 4
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#define _CLIENT_PLAYER_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "client/client.h"
|
||||
#include "client/object.h"
|
||||
#include "types.h"
|
||||
|
||||
extern struct ClientPlayer
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <stdlib.h>
|
||||
#include <dragontype/array.h>
|
||||
#include <dragonstd/array.h>
|
||||
#include "client/facecache.h"
|
||||
|
||||
static struct
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _FACECACHE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
v3s32 facecache_face(size_t i, v3s32 *base);
|
||||
size_t facecache_count(u32 size);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "client/mesh.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
void frustum_update(mat4x4 view_proj);
|
||||
bool frustum_is_visible(aabb3f32 box);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/bintree.h>
|
||||
#include <dragontype/list.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragonstd/bintree.h>
|
||||
#include <dragonstd/list.h>
|
||||
#include "client/font.h"
|
||||
#include "client/texture.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _INPUT_H_
|
||||
#define _INPUT_H_
|
||||
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
void input_tick(f64 dtime);
|
||||
void input_init();
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/array.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragonstd/array.h>
|
||||
#include "client/mesh.h"
|
||||
#include "client/texture.h"
|
||||
#include "client/vertex.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef struct {
|
||||
GLfloat x, y, z;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/bintree.h>
|
||||
#include <dragontype/list.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragonstd/bintree.h>
|
||||
#include <dragonstd/list.h>
|
||||
#include "types.h"
|
||||
#include "client/object.h"
|
||||
|
||||
extern struct Scene
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb/stb_image.h>
|
||||
#include <stdbool.h>
|
||||
#include <dragontype/list.h>
|
||||
#include <dragonstd/list.h>
|
||||
#include "client/client_config.h"
|
||||
#include "client/texture.h"
|
||||
#include "util.h"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _DAY_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
#define MINUTES_PER_HOUR 60
|
||||
#define HOURS_PER_DAY 24
|
||||
#define MINUTES_PER_DAY (HOURS_PER_DAY * MINUTES_PER_HOUR)
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _ENVIRONMENT_H_
|
||||
#define _ENVIRONMENT_H_
|
||||
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
f64 get_humidity(v3s32 pos);
|
||||
f64 get_temperature(v3s32 pos);
|
||||
|
|
94
src/map.c
94
src/map.c
|
@ -2,7 +2,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <endian.h/endian.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
// 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);
|
||||
|
||||
if (! my_decompress(data, size, decompressed, decompressed_size))
|
||||
return false;
|
||||
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);
|
||||
|
||||
unsigned char *ptr = decompressed;
|
||||
|
||||
ITERATE_MAPBLOCK {
|
||||
// node type
|
||||
u32 *type_ptr = buffer_read(&ptr, &decompressed_size, sizeof(u32));
|
||||
|
||||
if (! type_ptr)
|
||||
return false;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
13
src/map.h
13
src/map.h
|
@ -3,12 +3,11 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <dragontype/bintree.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragontype/list.h>
|
||||
#include <dragonstd/bintree.h>
|
||||
#include <dragonstd/list.h>
|
||||
#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
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/sh
|
||||
LUA_PATH="../deps/dragontype/?.lua;../deps/dragontype/?/init.lua" "../deps/dragontype/typegen.lua"
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#include <poll.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef _NETWORK_H_
|
||||
#define _NETWORK_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#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
|
43
src/node.c
43
src/node.c
|
@ -1,26 +1,9 @@
|
|||
#include "types.h"
|
||||
#include "map.h"
|
||||
#include "node.h"
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
||||
{
|
||||
|
|
10
src/node.h
10
src/node.h
|
@ -2,7 +2,7 @@
|
|||
#define _NODE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <dragontype/number.h>
|
||||
#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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _PERLIN_H_
|
||||
|
||||
#include <perlin/perlin.h>
|
||||
#include <dragontype/number.h>
|
||||
#include "types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef _BIOMES_H_
|
||||
#define _BIOMES_H_
|
||||
|
||||
#include <dragontype/number.h>
|
||||
#include "map.h"
|
||||
#include "perlin.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
|
||||
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]);
|
||||
|
||||
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]);
|
||||
Blob data = {0, NULL};
|
||||
Blob_write(&data, &extra->data);
|
||||
|
||||
char *mgsb_data;
|
||||
size_t mgsb_size;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,193 +1,93 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <dragonnet/addr.h>
|
||||
#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);
|
||||
ServerPlayer *player = peer->extra;
|
||||
|
||||
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();
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "Missing address\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
internal_error("missing port");
|
||||
if (! (server = dragonnet_listener_new(argv[1]))) {
|
||||
fprintf(stderr, "Failed to listen to connections\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_INET6,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = 0,
|
||||
.ai_flags = AI_NUMERICSERV | AI_PASSIVE,
|
||||
};
|
||||
char *address = dragonnet_addr_str(server->laddr);
|
||||
printf("Listening on %s\n", address);
|
||||
free(address);
|
||||
|
||||
struct addrinfo *info = NULL;
|
||||
|
||||
int gai_state = getaddrinfo(NULL, argv[1], &hints, &info);
|
||||
|
||||
if (gai_state != 0)
|
||||
internal_error(gai_strerror(gai_state));
|
||||
|
||||
int fd = socket(info->ai_family, info->ai_socktype, 0);
|
||||
|
||||
if (fd == -1)
|
||||
syscall_error("socket");
|
||||
|
||||
int flag = 1;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
|
||||
syscall_error("setsockopt");
|
||||
|
||||
if (bind(fd, info->ai_addr, info->ai_addrlen) == -1)
|
||||
syscall_error("bind");
|
||||
|
||||
if (listen(fd, 3) == -1)
|
||||
syscall_error("listen");
|
||||
|
||||
char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
|
||||
printf("Listening on %s\n", addrstr);
|
||||
free(addrstr);
|
||||
|
||||
freeaddrinfo(info);
|
||||
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;
|
||||
|
||||
signal_handlers_init();
|
||||
server_run(fd);
|
||||
|
||||
server_player_init();
|
||||
database_init();
|
||||
server_map_init();
|
||||
server_map_prepare_spawn();
|
||||
dragonnet_listener_run(server);
|
||||
|
||||
while (! interrupted)
|
||||
sched_yield();
|
||||
|
||||
printf("Shutting down\n");
|
||||
|
||||
dragonnet_listener_close(server);
|
||||
server_map_deinit();
|
||||
database_deinit();
|
||||
server_player_deinit();
|
||||
|
||||
dragonnet_listener_delete(server);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1,43 +1,8 @@
|
|||
#ifndef _SERVER_H_
|
||||
#define _SERVER_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <netinet/in.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragontype/list.h>
|
||||
#include "client/client_commands.h"
|
||||
#include "server/server_commands.h"
|
||||
#include "network.h"
|
||||
#include <dragonnet/listen.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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},
|
||||
};
|
|
@ -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
|
|
@ -11,23 +11,31 @@
|
|||
#include "util.h"
|
||||
|
||||
struct ServerMap server_map;
|
||||
static Server *server;
|
||||
|
||||
// utility functions
|
||||
|
||||
// send a block to a client and reset block request
|
||||
static void send_block(Client *client, MapBlock *block)
|
||||
// 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)
|
||||
{
|
||||
MapBlockExtraData *extra = block->extra;
|
||||
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);
|
||||
|
||||
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);
|
||||
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(ServerPlayer *player, MapBlock *block)
|
||||
{
|
||||
if (! within_simulation_distance(player, block->pos, server_config.simulation_distance))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#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
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <dragonstd/list.h>
|
||||
#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)
|
||||
*/
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _SERVER_PLAYER_H_
|
||||
#define _SERVER_PLAYER_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <dragonnet/peer.h>
|
||||
#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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef _TREES_H_
|
||||
#define _TREES_H_
|
||||
|
||||
#include <dragontype/list.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragonstd/list.h>
|
||||
#include "perlin.h"
|
||||
#include "types.h"
|
||||
|
||||
#define NUM_TREES 3
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#define VOXELCTXSTATE(ctx) (*((VoxelctxState *) (ctx)->statestack.first->key))
|
||||
|
||||
#include <linmath.h/linmath.h>
|
||||
#include <dragontype/list.h>
|
||||
#include <dragontype/number.h>
|
||||
#include <dragonstd/list.h>
|
||||
#include "types.h"
|
||||
#include "server/server_map.h"
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -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
|
143
src/util.c
143
src/util.c
|
@ -1,117 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <dragonport/asprintf.h>
|
||||
#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);
|
||||
}
|
||||
|
|
24
src/util.h
24
src/util.h
|
@ -1,18 +1,6 @@
|
|||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <dragontype/number.h>
|
||||
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue