gamestate: make some API endpoints optional

This commit is contained in:
Sebastian Krzyszkowiak 2018-07-05 20:42:51 +02:00
parent 125ff97fba
commit e293047aba
5 changed files with 41 additions and 21 deletions

View file

@ -147,7 +147,9 @@ SYMBOL_EXPORT void PauseGamestate(struct Game* game, const char* name) {
}
gs->paused = true;
game->_priv.current_gamestate = gs;
(*gs->api->Gamestate_Pause)(game, gs->data);
if (gs->api->Gamestate_Pause) {
(*gs->api->Gamestate_Pause)(game, gs->data);
}
PrintConsole(game, "Gamestate \"%s\" paused.", name);
} else {
PrintConsole(game, "Tried to pause nonexisitent gamestate \"%s\"", name);
@ -167,7 +169,9 @@ SYMBOL_EXPORT void ResumeGamestate(struct Game* game, const char* name) {
}
gs->paused = false;
game->_priv.current_gamestate = gs;
(*gs->api->Gamestate_Resume)(game, gs->data);
if (gs->api->Gamestate_Resume) {
(*gs->api->Gamestate_Resume)(game, gs->data);
}
PrintConsole(game, "Gamestate \"%s\" resumed.", name);
} else {
PrintConsole(game, "Tried to resume nonexisitent gamestate \"%s\"", name);

View file

@ -51,6 +51,7 @@ struct Gamestate {
struct Gamestate* next;
struct Gamestate_API* api;
ALLEGRO_BITMAP* fb;
int progressCount;
void* data;
};

View file

@ -98,7 +98,9 @@ SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) {
while (tmp) {
if (tmp->loaded) {
game->_priv.current_gamestate = tmp;
(*tmp->api->Gamestate_Reload)(game, tmp->data);
if (tmp->api->Gamestate_Reload) {
(*tmp->api->Gamestate_Reload)(game, tmp->data);
}
}
tmp = tmp->next;
}
@ -219,11 +221,10 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) {
struct GamestateLoadingThreadData* data = arg;
data->game->_priv.loading.inProgress = true;
al_set_new_bitmap_flags(data->bitmap_flags);
GamestateProgress(data->game);
double time = al_get_time();
data->gamestate->data = (*data->gamestate->api->Gamestate_Load)(data->game, &GamestateProgress);
PrintConsole(data->game, "[%s] Loading took %f seconds.", data->gamestate->name, al_get_time() - time);
if (data->game->_priv.loading.progress != *(data->gamestate->api->Gamestate_ProgressCount)) {
if (data->game->_priv.loading.progress != data->gamestate->progressCount) {
PrintConsole(data->game, "[%s] WARNING: Gamestate_ProgressCount does not match the number of progress invokations (%d)!", data->gamestate->name, data->game->_priv.loading.progress);
if (data->game->config.debug) {
PrintConsole(data->game, "(sleeping for 3 seconds...)");
@ -250,15 +251,18 @@ SYMBOL_INTERNAL void* ScreenshotThread(void* arg) {
return NULL;
}
SYMBOL_INTERNAL void GamestateProgress(struct Game* game) {
SYMBOL_INTERNAL void CalculateProgress(struct Game* game) {
struct Gamestate* tmp = game->_priv.loading.current;
game->_priv.loading.progress++;
float progressCount = *(tmp->api->Gamestate_ProgressCount) ? (float)*(tmp->api->Gamestate_ProgressCount) : 1;
float progress = ((game->_priv.loading.progress / progressCount) / (float)game->_priv.loading.toLoad) + (game->_priv.loading.loaded / (float)game->_priv.loading.toLoad);
game->loading_progress = progress;
float progress = ((game->_priv.loading.progress / (float)(tmp->progressCount + 1)) / (float)game->_priv.loading.toLoad) + (game->_priv.loading.loaded / (float)game->_priv.loading.toLoad);
if (game->config.debug) {
PrintConsole(game, "[%s] Progress: %d%% (%d/%d)", tmp->name, (int)(progress * 100), game->_priv.loading.progress, *(tmp->api->Gamestate_ProgressCount));
PrintConsole(game, "[%s] Progress: %d%% (%d/%d)", tmp->name, (int)(progress * 100), game->_priv.loading.progress, tmp->progressCount + 1);
}
game->loading_progress = progress;
}
SYMBOL_INTERNAL void GamestateProgress(struct Game* game) {
game->_priv.loading.progress++;
CalculateProgress(game);
#ifndef LIBSUPERDERPY_SINGLE_THREAD
// TODO: debounce thread synchronization to reduce overhead
al_lock_mutex(game->_priv.texture_sync_mutex);
@ -308,18 +312,21 @@ SYMBOL_INTERNAL bool LinkGamestate(struct Game* game, struct Gamestate* gamestat
if (!(gamestate->api->Gamestate_Draw = dlsym(gamestate->handle, "Gamestate_Draw"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Logic = dlsym(gamestate->handle, "Gamestate_Logic"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Load = dlsym(gamestate->handle, "Gamestate_Load"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Start = dlsym(gamestate->handle, "Gamestate_Start"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Pause = dlsym(gamestate->handle, "Gamestate_Pause"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Resume = dlsym(gamestate->handle, "Gamestate_Resume"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Stop = dlsym(gamestate->handle, "Gamestate_Stop"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Unload = dlsym(gamestate->handle, "Gamestate_Unload"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Start = dlsym(gamestate->handle, "Gamestate_Start"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Stop = dlsym(gamestate->handle, "Gamestate_Stop"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_ProcessEvent = dlsym(gamestate->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Reload = dlsym(gamestate->handle, "Gamestate_Reload"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_ProgressCount = dlsym(gamestate->handle, "Gamestate_ProgressCount"))) { GS_ERROR; }
// optional
gamestate->api->Gamestate_Pause = dlsym(gamestate->handle, "Gamestate_Pause");
gamestate->api->Gamestate_Resume = dlsym(gamestate->handle, "Gamestate_Resume");
gamestate->api->Gamestate_Reload = dlsym(gamestate->handle, "Gamestate_Reload");
gamestate->api->Gamestate_ProgressCount = dlsym(gamestate->handle, "Gamestate_ProgressCount");
if (gamestate->api->Gamestate_ProgressCount) {
gamestate->progressCount = *gamestate->api->Gamestate_ProgressCount;
}
#undef GS_ERROR
@ -340,6 +347,7 @@ SYMBOL_INTERNAL struct Gamestate* AllocateGamestate(struct Game* game, const cha
tmp->pending_unload = false;
tmp->next = NULL;
tmp->api = NULL;
tmp->progressCount = 0;
return tmp;
}
@ -541,7 +549,9 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) {
CloseGamestate(game, tmp);
tmp->name = name;
if (OpenGamestate(game, tmp) && LinkGamestate(game, tmp)) {
tmp->api->Gamestate_Reload(game, tmp->data);
if (tmp->api->Gamestate_Reload) {
tmp->api->Gamestate_Reload(game, tmp->data);
}
}
tmp = tmp->next;
}

View file

@ -75,6 +75,7 @@ void Console_Load(struct Game* game);
void Console_Unload(struct Game* game);
void* GamestateLoadingThread(void* arg);
void* ScreenshotThread(void* arg);
void CalculateProgress(struct Game* game);
void GamestateProgress(struct Game* game);
void* AddGarbage(struct Game* game, void* data);
void ClearGarbage(struct Game* game);

View file

@ -408,7 +408,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
}
if (tmp->api) {
PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
game->_priv.loading.progress = -1;
game->_priv.loading.progress = 0;
game->_priv.loading.current = tmp;
game->_priv.current_gamestate = tmp;
@ -417,6 +417,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
game->_priv.loading.inProgress = true;
game->_priv.loading.time = al_get_time();
CalculateProgress(game);
#ifndef LIBSUPERDERPY_SINGLE_THREAD
al_run_detached_thread(GamestateLoadingThread, &data);
while (game->_priv.loading.inProgress) {
@ -443,6 +444,9 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
al_set_new_bitmap_flags(data.bitmap_flags);
ReloadShaders(game, false);
game->_priv.loading.progress++;
CalculateProgress(game);
PrintConsole(game, "Gamestate \"%s\" loaded successfully.", tmp->name);
game->_priv.loading.loaded++;