Functional hot reloading

This commit is contained in:
Phireh 2024-12-16 21:40:04 +01:00
commit 23bafb943f
4 changed files with 58 additions and 13 deletions

View file

@ -18,6 +18,7 @@
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/stat.h>
// libevdev
#include <libevdev-1.0/libevdev/libevdev.h>
// generated header using wayland-scanner
@ -70,12 +71,14 @@ error_level_t error_verbosity = { ERROR_LEVEL_DEBUG };
typedef void (*simulate_frame_fn)(game_state_t*);
/* Game layer */
/* Game layer and hot reload */
typedef struct {
simulate_frame_fn simulate_frame;
} game_api_t;
game_api_t game_api = {};
time_t hr_timestamp = 0;
void *dlhandle = NULL;
char *egl_s(int code)
{
@ -742,16 +745,25 @@ int main()
wl_surface_commit(surface);
// Trying to link with game layer
void *dlhandle = dlopen("./game.so", RTLD_NOW);
dlhandle = dlopen("./game.so", RTLD_NOW | RTLD_LOCAL);
if (!dlhandle)
{
console_err_ss(MODULE_HOTRELOAD, "Could not load game layer\n");
dlerror();
dlerror();
}
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
struct stat fs;
if (stat("./game.so", &fs) == -1)
console_err_ss(MODULE_HOTRELOAD, "Could not get info for game library: %s\n", strerror(errno));
char *dlerr = NULL;
if ((dlerr = dlerror()))
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
{
hr_timestamp = fs.st_mtime;
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
char *dlerr = NULL;
if ((dlerr = dlerror()))
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
}
// Main event loop
int framecount = 0;
@ -759,6 +771,37 @@ int main()
{
wl_display_dispatch_pending(display);
// TODO: Do not try to hot-reload every frame. Lmao
struct stat file_stats;
if (stat("./game.so", &file_stats) == -1)
{
console_err_ss(MODULE_HOTRELOAD, "Could not get info for game library: %s\n", strerror(errno));
}
else if (hr_timestamp < file_stats.st_mtime)
{
console_log_ss(MODULE_HOTRELOAD, "Game library has changed: trying to hot reload\n");
// NOTE: We cannot load new symbols from the same path unless we close the currently open handle.
// However, until the linker is done with the file it will fail on dlopen.
// For now we just busywait trying to link it.
dlclose(dlhandle);
while (!(dlhandle = dlopen("./game.so", RTLD_NOW | RTLD_LOCAL)));
hr_timestamp = fs.st_mtime;
game_api.simulate_frame = (simulate_frame_fn)dlsym(dlhandle, "simulate_frame");
char *dlerr = NULL;
if ((dlerr = dlerror()))
console_err_ss(MODULE_HOTRELOAD, "Could not link game layer: %s\n", dlerr);
hr_timestamp = file_stats.st_mtime;
char *error_string = dlerror();
if (error_string)
console_err_ss(MODULE_HOTRELOAD, "Error loading game code: %s\n", error_string);
console_log_ss(MODULE_HOTRELOAD, "Successfully hot reloaded game layer\n");
}
/* Controller input handling */
if (libevdev_get_fd(libevdev) != -1) // check if we actually found a controller to query
{
@ -848,8 +891,9 @@ int main()
game_state.frame = framecount;
// TODO: Get delta time since last frame
game_state.dt = 0;
game_api.simulate_frame(&game_state);
if (game_state.version != 1)
console_debug_ss(MODULE_HOTRELOAD, "Version %d\n", game_state.version);
//console_debug_ss(MODULE_WAYLAND, "Frame %d\n", framecount);
glClearColor(0.5, 0.3, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);