Working HTML5 version

This commit is contained in:
2024-01-29 00:10:31 +01:00
parent 410c3d217e
commit 409d9027ef
11 changed files with 108 additions and 30 deletions

View File

@@ -17,6 +17,9 @@
#include "pathfinding.h"
#include "sounds.h"
// Constants
const char *SETTINGS_PATH = "settings.ini";
// Constants end
ECS_COMPONENT_DECLARE(Game);
ECS_COMPONENT_DECLARE(InputState);
@@ -32,7 +35,20 @@ void update(float dt, void *userData);
void render(float dt, void *userData);
void imguiRender(float dt, void *userData);
static bool loopPaused = true;
extern void loopPause(void) {
loopPaused = true;
}
extern void loopResume(void) {
loopPaused = false;
}
#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif
bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
appDesc->width = 1280;
appDesc->height = 720;
@@ -48,6 +64,25 @@ bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
appDesc->userData = NULL;
//SetConfigFlags(FLAG_WINDOW_RESIZABLE);
#ifdef EMSCRIPTEN
EM_ASM(
FS.mkdir('/game');
FS.mount(IDBFS, {}, '/game');
FS.syncfs(true, function (err) {
console.log("resumed");
Module.ccall('loopResume', 'void', ['void']);
});
console.log('/game mounted');
/*
* Note: FS.syncfs is async so we need to pause the
* main loop until it finishes :/
*/
Module.ccall('loopPause', 'void', ['void']);
);
loopPaused = true;
#else
loopPaused = false;
#endif
return true;
}
@@ -63,14 +98,42 @@ int cmpDrawData(const void *a, const void *b) {
return cmpVal;
}
bool serializeOptions(const char *path, const Options *opts) {
#ifdef EMSCRIPTEN
char buf[4096];
snprintf(buf, sizeof(buf), "%s%s", "/game/", path);
path = buf;
#endif
bzLogInfo("write path: %s", path);
FILE *f = fopen(path, "w");
if (!f) return false;
size_t numWritten = fwrite(opts, sizeof(*opts), 1, f);
fclose(f);
#ifdef EMSCRIPTEN
// Sync FS
EM_ASM(
FS.syncfs(false, function (err) {
});
);
#endif
return numWritten == 1;
}
bool deserializeOptions(const char *path, Options *optsOut) {
#ifdef EMSCRIPTEN
char buf[4096];
snprintf(buf, sizeof(buf), "%s%s", "/game/", path);
path = buf;
#endif
bzLogInfo("read path: %s", path);
FILE *f = fopen(path, "r");
bzLogInfo("start reading");
if (!f) return false;
bzLogInfo("reading");
Options opts;
size_t numRead = fread(&opts, sizeof(opts), 1, f);
fclose(f);
@@ -143,7 +206,7 @@ bool init(void *userData) {
}
setScreen(game, SCREEN_MAIN_MENU);
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
game->stackAlloc = bzStackAllocCreate(1 * 1000 * 1000); // 1 MB
// init pools
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
.objectSize = sizeof(PathData),
@@ -252,22 +315,12 @@ bool init(void *userData) {
loadMap(game, "assets/maps/main_menu_01.tmj");
game->debug.drawMapColliders = true;
game->debug.drawSpatialGrid = true;
game->debug.drawPath = true;
game->debug.drawMapColliders = false;
game->debug.drawSpatialGrid = false;
game->debug.drawPath = false;
game->debug.inspecting = bzArrayCreate(ecs_entity_t, 10);
// Load settings
const char *workDir = GetApplicationDirectory();
char buf[FILENAME_MAX];
snprintf(buf, sizeof(buf), "%s%s", workDir, "settings");
Options opts;
if (deserializeOptions(buf, &opts)) {
game->options = opts;
} else {
game->options = getDefaultOptions();
}
return true;
}
@@ -277,10 +330,7 @@ void deinit(void *userData) {
InputState *input = ecs_singleton_get_mut(ECS, InputState);
SoundState *sounds = ecs_singleton_get_mut(ECS, SoundState);
const char *workDir = GetApplicationDirectory();
char buf[FILENAME_MAX];
snprintf(buf, sizeof(buf), "%s%s", workDir, "settings");
serializeOptions(buf, &game->options);
serializeOptions(SETTINGS_PATH, &game->options);
unloadMap(game);
@@ -320,6 +370,8 @@ void deinit(void *userData) {
void update(float dt, void *userData) {
if (loopPaused)
return;
BZ_UNUSED(userData);
char titleBuf[32];
@@ -329,6 +381,22 @@ void update(float dt, void *userData) {
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
{
static bool optsLoaded = false;
if (!optsLoaded) {
// Load settings
const char *path = SETTINGS_PATH;
Options opts;
if (deserializeOptions(path, &opts)) {
game->options = opts;
} else {
game->options = getDefaultOptions();
}
optsLoaded = true;
}
}
game->screenPrevFrame = game->screen;
if (game->screen != game->nextScreen)
game->screen = game->nextScreen;
@@ -487,6 +555,8 @@ static void renderGame(Game *game, float dt) {
}
void render(float dt, void *userData) {
if (loopPaused)
return;
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
@@ -600,9 +670,9 @@ void imguiRender(float dt, void *userData) {
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
igBegin("Debug Menu", NULL, 0);
igText("PathData pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
igText("BTNode pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNode));
igText("BTNodeState pool available: %llu", bzObjectPoolGetNumFree(game->pools.btNodeState));
igText("PathData pool available: %lu", bzObjectPoolGetNumFree(game->pools.pathData));
igText("BTNode pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNode));
igText("BTNodeState pool available: %lu", bzObjectPoolGetNumFree(game->pools.btNodeState));
const char *inputState = "NONE";
switch (input->state) {
case INPUT_NONE: