aboutsummaryrefslogtreecommitdiff
path: root/ark/src/world.c
diff options
context:
space:
mode:
Diffstat (limited to 'ark/src/world.c')
-rw-r--r--ark/src/world.c199
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);
+}