diff --git a/README.gmi b/README.gmi index 7307817..ea2c791 100644 --- a/README.gmi +++ b/README.gmi @@ -5,8 +5,12 @@ Note: I'm not galaxy-brained enough to do the full idea at the moment, so this i ## Build from Source ### Dependencies +#### All * CMake + +#### Common Library * Lua 5.4 +* Jansson ### Building ``` diff --git a/client/src/main.c b/client/src/main.c index 50a0446..37c6b71 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1,10 +1,10 @@ // main.c #include -#include #include #include +#include "world.h" #include "error.h" #include "sock.h" @@ -15,15 +15,25 @@ int main(void) { err = sock_init(&sock); if (err) goto handle_error; - char ibuf[1028] = { 0 }; - char obuf[1028] = { 0 }; - strcpy(obuf, "Hello, world!\n"); + char ibuf[1024] = { 0 }; + char obuf[1024] = { 0 }; - // Just echoing everything back for now - write(sock, obuf, 1028); - int rc = read(sock, ibuf, 1028); + // TODO: I skipped out on most error handling here + read(sock, ibuf, 1024); - if (rc > 0) printf("%s", ibuf); + struct json_error_t json_err; + struct json_t *json = json_loads(ibuf, 0, &json_err); + + struct world_t world = { 0 }; + world_deserialise(&world, json); + + printf("CLIENT: (%zu %zu)\n", world.height, world.width); + + struct json_t *new_json; + world_serialise(&world, &new_json); + + json_dumpb(new_json, obuf, 1024, 0); + write(sock, obuf, 1024); close(sock); return ERR_OK; diff --git a/client/src/sock.c b/client/src/sock.c index 9362017..b14179e 100644 --- a/client/src/sock.c +++ b/client/src/sock.c @@ -16,8 +16,7 @@ enum error_t sock_init(int *sockptr) { struct sockaddr_un sa = { 0 }; sa.sun_family = AF_UNIX; - strcpy(sa.sun_path, "/tmp/swd.sock"); - // Socket path should be a shared setting between server and client + strcpy(sa.sun_path, SOCK_PATH); if (connect(sock, (struct sockaddr *)&sa, sizeof(sa))) goto sock_error; diff --git a/client/src/sock.h b/client/src/sock.h index fa54a69..e9d095b 100644 --- a/client/src/sock.h +++ b/client/src/sock.h @@ -3,6 +3,8 @@ #include "error.h" +#define SOCK_PATH "/tmp/swd.sock" + enum error_t sock_init(int *); #endif diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e151cc1..7b035fa 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -10,7 +10,9 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/common/include) find_package(PkgConfig REQUIRED) -pkg_check_modules(LUA REQUIRED lua) -target_link_libraries(${PROJECT_NAME} ${LUA_LIBRARIES}) -target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIRS}) +pkg_check_modules(LUA REQUIRED lua) +pkg_check_modules(JANSSON REQUIRED jansson) + +target_link_libraries(${PROJECT_NAME} ${LUA_LIBRARIES} ${JANSSON_LIBRARIES}) +target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS}) diff --git a/common/include/error.h b/common/include/error.h index 91adee6..534a4eb 100644 --- a/common/include/error.h +++ b/common/include/error.h @@ -9,6 +9,8 @@ enum error_t { ERR_FORK, ERR_SETSID, ERR_SOCKET, + ERR_JSON_SERIALISE, + ERR_JSON_DESERIALISE, __ERR_COUNT, }; diff --git a/common/include/world.h b/common/include/world.h index 5d9678c..7d2222b 100644 --- a/common/include/world.h +++ b/common/include/world.h @@ -3,6 +3,8 @@ #include +#include + #include "error.h" #include "entity/registry.h" #include "entity/entity.h" @@ -20,6 +22,20 @@ struct world_t { enum error_t world_init(struct world_t *, size_t, size_t); void world_free(struct world_t *); +// json_t doesn't store the json data itself; the value of the pointer is +// apparently needed for jansson to use the data, so I need a double pointer +// +// TODO +// Right now, to serialise and deserialise again you have to call: +// 1. world_serialise() | world_t -> json_t +// 2. json_dumpX() | json_t -> char * +// 3. json_loadX() | char * -> json_t +// 4. world_deserialise() | json_t -> world_t +// +// Perhaps these two functions should go directly between world_t and char * +enum error_t world_serialise(struct world_t *, struct json_t **); +enum error_t world_deserialise(struct world_t *, struct json_t *); + enum error_t world_register_entity(struct world_t *, char const *, char); enum error_t world_place_entity(struct world_t *, size_t, size_t, size_t); diff --git a/common/src/error.c b/common/src/error.c index 191bd9d..e033003 100644 --- a/common/src/error.c +++ b/common/src/error.c @@ -10,6 +10,8 @@ char const *const ERROR_STRS[] = { "FORK", "SETSID", "SOCKET", + "JSON SERIALISATION", + "JSON DESERIALISATION", }; diff --git a/common/src/world.c b/common/src/world.c index a4ba799..2880279 100644 --- a/common/src/world.c +++ b/common/src/world.c @@ -34,14 +34,50 @@ enum error_t world_init(struct world_t *self, size_t height, size_t width) { void world_free(struct world_t *self) { + assert(self != NULL); + entity_registry_free(&self->registered_entities); } +enum error_t world_serialise(struct world_t *self, struct json_t **json) { + assert(self != NULL); + // TODO: (de)serialise the following: + // struct entity_t entities[MAX_ENTITIES]; + // struct entity_registry_t registered_entities; + + struct json_t *maybe_json = json_pack("{s:I,s:I}", + "height", self->height, + "width", self->width + ); + if (maybe_json == NULL) return ERR_JSON_SERIALISE; + + *json = maybe_json; + return ERR_OK; +} + + +enum error_t world_deserialise(struct world_t *self, struct json_t *json) { + assert(self != NULL); + assert(json != NULL); + + int err = json_unpack(json, "{s:I,s:I}", + "height", &self->height, + "width", &self->width + ); + if (err < 0) return ERR_JSON_DESERIALISE; + + return ERR_OK; +} + + enum error_t world_register_entity( struct world_t *self, char const *name, char tile ) { + assert(self != NULL); + assert(name != NULL); + enum error_t err; struct entity_registry_t *registry = &self->registered_entities; @@ -57,6 +93,8 @@ enum error_t world_register_entity( static size_t world_find_empty_entity(struct world_t const *self) { + assert(self != NULL); + for (size_t i = 0; i < MAX_ENTITIES; i++) if (self->entities[i].id == 0) return i; diff --git a/server/src/data.h b/server/src/data.h index c5c8103..5295ca5 100644 --- a/server/src/data.h +++ b/server/src/data.h @@ -2,8 +2,10 @@ #define DAEMON_DATA_H #include "world.h" +#include "opts.h" struct data_t { + struct options_t options; struct world_t world; int socket; diff --git a/server/src/main.c b/server/src/main.c index 57f7bb3..c6c8c87 100644 --- a/server/src/main.c +++ b/server/src/main.c @@ -22,11 +22,34 @@ static void handle_signal(int signal_no) { } -enum error_t game_loop(struct data_t *data) { - uint8_t buffer[1024] = { 0 }; +#define LOGMSG(options, fmt, ...) \ + ((options)->daemonise ? \ + syslog(LOG_NOTICE, (fmt), __VA_ARGS__) : \ + (void)printf((fmt), __VA_ARGS__)) - read(data->socket_accept, buffer, 1024); - write(data->socket_accept, buffer, 1024); + +enum error_t game_loop(struct data_t *data) { + enum error_t err = ERR_OK; + char obuf[1024] = { 0 }; + char ibuf[1024] = { 0 }; + + // TODO: I skipped out on most error handling here + struct json_t *json; + err = world_serialise(&data->world, &json); + if (err != ERR_OK) return err; + + json_dumpb(json, obuf, 1024, 0); + write(data->socket_accept, obuf, 1024); + + read(data->socket_accept, ibuf, 1024); + json = json_loads(ibuf, 0, NULL); + + struct world_t returned_world; + world_deserialise(&returned_world, json); + LOGMSG(&data->options, "SERVER: (%zu %zu) -> (%zu %zu)\n", + data->world.height, data->world.width, + returned_world.height, returned_world.width + ); return ERR_OK; } @@ -42,13 +65,12 @@ int main(int argc, char **argv) { signal(SIGTERM, handle_signal); // Handle commandline options - struct options_t options = { 0 }; - opts_default(&options); + opts_default(&data.options); - err = opts_parse(&options, argc, argv); + err = opts_parse(&data.options, argc, argv); if (err) goto handle_error_pre_opts; - err = opts_init(&options); + err = opts_init(&data.options); if (err) goto handle_error; // World initialisation @@ -61,42 +83,21 @@ int main(int argc, char **argv) { err = world_place_entity(&data.world, 1, 3, 7); if (err) goto handle_error_world; - // Temporary code because I just realised I need to properly serialise - // data because pointers don't work cross-socket - // TODO: Serialise to JSON - const char *fmt = "%zu (%s) (%zu, %zu) '%c'\n"; - struct entity_t const *const entity = &data.world.entities[0]; - struct entity_registrant_t const *const registrant = - &data.world.registered_entities.entities[entity->id]; - - if (options.daemonise) - syslog(LOG_NOTICE, fmt, - entity->id, registrant->name, - entity->x, entity->y, - registrant->tile - ); - else - printf(fmt, - entity->id, registrant->name, - entity->x, entity->y, - registrant->tile - ); - // Socket handling and run gameloop err = sock_loop(&data, game_loop); if (err) goto handle_error; // Deinitialisation world_free(&data.world); - opts_free(&options); + opts_free(&data.options); return ERR_OK; handle_error_world: world_free(&data.world); handle_error: - if (options.daemonise) syslog(LOG_ERR, "%s", ERROR_STRS[err]); - opts_free(&options); + if (data.options.daemonise) syslog(LOG_ERR, "%s", ERROR_STRS[err]); + opts_free(&data.options); handle_error_pre_opts: printf("ERROR: %s\n", ERROR_STRS[err]);