diff options
Diffstat (limited to 'ark/src/world.c')
| -rw-r--r-- | ark/src/world.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/ark/src/world.c b/ark/src/world.c new file mode 100644 index 0000000..e7641ed --- /dev/null +++ b/ark/src/world.c @@ -0,0 +1,199 @@ +#include "world.h" + +#include <ctype.h> +#include <dlfcn.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +/* Utility function for showing the marshalled states as hex code */ +static void shx(uint8_t *state, uint32_t sz) +{ + uint32_t i = 0; + while (i < sz) { + for (int j = 0; j < 16; ++j) { + if (i < sz) { + printf("%02x ", (unsigned int)state[i]); + } + else { + printf(" "); + } + ++i; + } + + i -= 16; + + printf(" "); + + for (int j = 0; j < 16; ++j) { + if (i < sz) { + if (isprint(state[i]) && !isspace(state[i])) { + printf("%c", state[i]); + } + else { + printf("."); + } + } + else { + printf(" "); + } + ++i; + } + printf("\n"); + } +} + +int load_world_from_dl_(dlhandle_t dl, world_t *world); + +static void lock(world_t *world) { pthread_mutex_lock(&world->lock); }; + +static void unlock(world_t *world) { pthread_mutex_unlock(&world->lock); }; + +static int load_world_from_file_(int argc, char **argv, const char *filename, + world_t *world) +{ + dlhandle_t lib = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); + int ec = 0; + + if (!lib) { + fprintf(stderr, "Failed to open library: %s: %s\n", filename, dlerror()); + ec = 1; + goto end; + } + + printf("Loading file.\n"); + ec = load_world_from_dl_(lib, world); + + if (ec) { + goto end; + } + + strncpy(world->filename, filename, sizeof(world->filename)); + world->argc = argc; + world->argv = argv; + + world->arkworld_export_load(world->argc, world->argv); +end: + return ec; +} + +static void maybe_run_metaload(int argc, char **argv, world_t *world) +{ + static char *loaded_worlds[12]; + int i; + for (i = 0; i < 12 && loaded_worlds[i]; ++i) { + if (strcmp(loaded_worlds[i], world->world_name) == 0) { + return; // World is already loaded + } + } + loaded_worlds[i] = strdup(world->world_name); + + printf("First time loading %s, running metaload.\n", world->world_name); + if (world->arkworld_export_metaload) { + world->arkworld_export_metaload(argc, argv); + } +} + +int load_world_from_file(int argc, char **argv, const char *filename, + world_t *world) +{ + memset(world, 0, sizeof(*world)); + + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) { + perror("pthread_mutexattr_init"); + return 1; + } + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) { + perror("pthread_mutexattr_settype"); + return 1; + } + + if (pthread_mutex_init(&world->lock, &attr)) { + pthread_mutexattr_destroy(&attr); + perror("pthread_mutexattr_init"); + return 1; + } + pthread_mutexattr_destroy(&attr); + int rc = load_world_from_file_(argc, argv, filename, world); + + if (rc == 0) { + maybe_run_metaload(argc, argv, world); + } + + return rc; +} + +int world_hot_reload_same_state(world_t *world) +{ + char filename_cpy[PATH_MAX]; + strncpy(filename_cpy, world->filename, sizeof(filename_cpy)); + return world_hot_reload(world->argc, world->argv, filename_cpy, world); +} + +int world_hot_reload(int argc, char **argv, const char *filepath, + world_t *world) +{ + int ec = 0; + uint32_t sz = 0; + uint8_t *marshalled_state = NULL; + + printf("Hot Reloading %s\n", world->world_name); + lock(world); + + printf("Marshalling state ...\n"); + marshalled_state = world->arkworld_export_preserve(world->state, &sz); + + printf("Calling teardown ...\n"); + world->arkworld_export_release(world->state); + + printf("State Marshalled:\n"); + shx(marshalled_state, sz); + + printf("Unloading old library handle.\n"); + if (dlclose(world->library_handle)) { + printf("Could not close library handle: %s\n", dlerror()); + } + + if ((ec = load_world_from_file_(argc, argv, filepath, world))) { + goto fail; + } + + printf("Hot starting world ...\n"); + world->state = world->arkworld_export_rebirth(world, marshalled_state, sz); + +fail: + free(marshalled_state); + unlock(world); + return ec; +} + +void world_run_requested_actions(world_t *world) +{ + lock(world); + requested_action_t requested_actions[MAX_QUEUED_ACTIONS]; + size_t n_requested_actions = world->n_requested_actions; + memcpy(&requested_actions, world->requested_actions, + sizeof(requested_actions)); + world->n_requested_actions = 0; + unlock(world); + + size_t i; + for (i = 0; i < n_requested_actions; ++i) { + requested_actions[i].action(world, requested_actions[i].str_arg); + if (requested_actions[i].arg_dtor) { + requested_actions[i].arg_dtor(requested_actions[i].ptr_arg); + } + } +} + +void world_cold_start(world_t *world) +{ + lock(world); + world->state = world->arkworld_export_enworld(world); + unlock(world); +} |