partially done work on total source tree rework, separation of engine context and game context, generalization of renderer for different backends as well as web platform target
This commit is contained in:
142
src/game_object/twn_linux_game_object_c.h
Normal file
142
src/game_object/twn_linux_game_object_c.h
Normal file
@ -0,0 +1,142 @@
|
||||
#include "townengine/twn_game_object.h"
|
||||
#include "townengine/context.h"
|
||||
|
||||
#include <x-watcher.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
#define GAME_OBJECT_PATH "./libgame.so"
|
||||
#define MODIFIED_TICKS_MERGED 10
|
||||
|
||||
|
||||
static void (*game_tick_callback)(void);
|
||||
static void (*game_end_callback)(void);
|
||||
|
||||
static x_watcher *watcher;
|
||||
static void *handle = NULL;
|
||||
|
||||
static uint64_t last_tick_modified;
|
||||
static bool loaded_after_modification = true;
|
||||
static SDL_mutex *lock;
|
||||
|
||||
|
||||
static void load_game_object(void) {
|
||||
/* needs to be closed otherwise symbols aren't resolved again */
|
||||
if (handle) {
|
||||
dlclose(handle);
|
||||
handle = NULL;
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
}
|
||||
|
||||
void *new_handle = dlopen(GAME_OBJECT_PATH, RTLD_LAZY);
|
||||
if (!new_handle) {
|
||||
log_critical("Hot Reload Error: Cannot open game code shared object (%s)", dlerror());
|
||||
goto ERR_OPENING_SO;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
game_tick_callback = (void (*)(void))dlsym(new_handle, "game_tick");
|
||||
if (!game_tick_callback) {
|
||||
CRY("Hot Reload Error", "game_tick_callback() symbol wasn't found");
|
||||
goto ERR_GETTING_PROC;
|
||||
}
|
||||
|
||||
game_end_callback = (void (*)(void))dlsym(new_handle, "game_end");
|
||||
if (!game_end_callback) {
|
||||
CRY("Hot Reload Error", "game_end_callback() symbol wasn't found");
|
||||
goto ERR_GETTING_PROC;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
handle = new_handle;
|
||||
|
||||
if (ctx.tick_count != 0)
|
||||
log_info("Game object was reloaded\n");
|
||||
|
||||
return;
|
||||
|
||||
ERR_GETTING_PROC:
|
||||
dlclose(new_handle);
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
|
||||
ERR_OPENING_SO:
|
||||
SDL_UnlockMutex(lock);
|
||||
|
||||
}
|
||||
|
||||
static void watcher_callback(XWATCHER_FILE_EVENT event,
|
||||
const char *path,
|
||||
int context,
|
||||
void *data)
|
||||
{
|
||||
(void)context;
|
||||
(void)path;
|
||||
(void)data;
|
||||
|
||||
switch(event) {
|
||||
case XWATCHER_FILE_MODIFIED:
|
||||
SDL_LockMutex(lock);
|
||||
last_tick_modified = ctx.tick_count;
|
||||
loaded_after_modification = false;
|
||||
SDL_UnlockMutex(lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void game_object_load(void) {
|
||||
watcher = xWatcher_create();
|
||||
|
||||
xWatcher_reference dir;
|
||||
dir.path = GAME_OBJECT_PATH;
|
||||
dir.callback_func = watcher_callback;
|
||||
|
||||
xWatcher_appendFile(watcher, &dir);
|
||||
xWatcher_start(watcher);
|
||||
|
||||
lock = SDL_CreateMutex();
|
||||
load_game_object();
|
||||
}
|
||||
|
||||
|
||||
void game_object_unload(void) {
|
||||
game_end_callback();
|
||||
xWatcher_destroy(watcher);
|
||||
watcher = NULL;
|
||||
dlclose(handle);
|
||||
handle = NULL;
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
SDL_DestroyMutex(lock);
|
||||
}
|
||||
|
||||
|
||||
bool game_object_try_reloading(void) {
|
||||
bool result = false;
|
||||
|
||||
/* only load the modified library after some time, as compilers make a lot of modifications */
|
||||
SDL_LockMutex(lock);
|
||||
if (ctx.tick_count - last_tick_modified > MODIFIED_TICKS_MERGED &&
|
||||
!loaded_after_modification) {
|
||||
load_game_object();
|
||||
loaded_after_modification = true;
|
||||
result = true;
|
||||
} SDL_UnlockMutex(lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void game_object_tick(void) {
|
||||
game_tick_callback();
|
||||
}
|
21
src/game_object/twn_static_game_object_c.h
Normal file
21
src/game_object/twn_static_game_object_c.h
Normal file
@ -0,0 +1,21 @@
|
||||
#include "townengine/twn_game_object.h"
|
||||
#include "townengine/game_api.h"
|
||||
|
||||
|
||||
void game_object_load(void) {
|
||||
}
|
||||
|
||||
|
||||
void game_object_unload(void) {
|
||||
game_end();
|
||||
}
|
||||
|
||||
|
||||
bool game_object_try_reloading(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void game_object_tick(void) {
|
||||
game_tick();
|
||||
}
|
88
src/game_object/twn_win32_game_object_c.h
Normal file
88
src/game_object/twn_win32_game_object_c.h
Normal file
@ -0,0 +1,88 @@
|
||||
#include "townengine/twn_game_object.h"
|
||||
#include "townengine/context.h"
|
||||
|
||||
#include <errhandlingapi.h>
|
||||
#include <libloaderapi.h>
|
||||
|
||||
|
||||
#define GAME_OBJECT_PATH "libgame.dll"
|
||||
|
||||
|
||||
static void (*game_tick_callback)(void);
|
||||
static void (*game_end_callback)(void);
|
||||
|
||||
static void *handle = NULL;
|
||||
|
||||
|
||||
static void load_game_object(void) {
|
||||
/* needs to be closed otherwise symbols aren't resolved again */
|
||||
if (handle) {
|
||||
FreeLibrary(handle);
|
||||
handle = NULL;
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
}
|
||||
|
||||
void *new_handle = LoadLibraryA(GAME_OBJECT_PATH);
|
||||
if (!new_handle) {
|
||||
log_critical("Hot Reload Error: Cannot open game code shared object (%s)", GetLastError());
|
||||
goto ERR_OPENING_SO;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
game_tick_callback = (void (*)(void))GetProcAddress(new_handle, "game_tick");
|
||||
if (!game_tick_callback) {
|
||||
CRY("Hot Reload Error", "game_tick_callback() symbol wasn't found");
|
||||
goto ERR_GETTING_PROC;
|
||||
}
|
||||
|
||||
game_end_callback = (void (*)(void))GetProcAddress(new_handle, "game_end");
|
||||
if (!game_end_callback) {
|
||||
CRY("Hot Reload Error", "game_end_callback() symbol wasn't found");
|
||||
goto ERR_GETTING_PROC;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
handle = new_handle;
|
||||
|
||||
if (ctx.tick_count != 0)
|
||||
log_info("Game object was reloaded\n");
|
||||
|
||||
return;
|
||||
|
||||
ERR_GETTING_PROC:
|
||||
FreeLibrary(new_handle);
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
|
||||
ERR_OPENING_SO:
|
||||
die_abruptly();
|
||||
}
|
||||
|
||||
|
||||
void game_object_load(void) {
|
||||
load_game_object();
|
||||
}
|
||||
|
||||
|
||||
void game_object_unload(void) {
|
||||
game_end_callback();
|
||||
FreeLibrary(handle);
|
||||
handle = NULL;
|
||||
game_tick_callback = NULL;
|
||||
game_end_callback = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* doesn't support reloading because of problems with file watching */
|
||||
bool game_object_try_reloading(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void game_object_tick(void) {
|
||||
game_tick_callback();
|
||||
}
|
Reference in New Issue
Block a user