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; gs->paused = true;
game->_priv.current_gamestate = gs; 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); PrintConsole(game, "Gamestate \"%s\" paused.", name);
} else { } else {
PrintConsole(game, "Tried to pause nonexisitent gamestate \"%s\"", name); 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; gs->paused = false;
game->_priv.current_gamestate = gs; 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); PrintConsole(game, "Gamestate \"%s\" resumed.", name);
} else { } else {
PrintConsole(game, "Tried to resume nonexisitent gamestate \"%s\"", name); PrintConsole(game, "Tried to resume nonexisitent gamestate \"%s\"", name);

View file

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

View file

@ -98,7 +98,9 @@ SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) {
while (tmp) { while (tmp) {
if (tmp->loaded) { if (tmp->loaded) {
game->_priv.current_gamestate = tmp; 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; tmp = tmp->next;
} }
@ -219,11 +221,10 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) {
struct GamestateLoadingThreadData* data = arg; struct GamestateLoadingThreadData* data = arg;
data->game->_priv.loading.inProgress = true; data->game->_priv.loading.inProgress = true;
al_set_new_bitmap_flags(data->bitmap_flags); al_set_new_bitmap_flags(data->bitmap_flags);
GamestateProgress(data->game);
double time = al_get_time(); double time = al_get_time();
data->gamestate->data = (*data->gamestate->api->Gamestate_Load)(data->game, &GamestateProgress); 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); 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); 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) { if (data->game->config.debug) {
PrintConsole(data->game, "(sleeping for 3 seconds...)"); PrintConsole(data->game, "(sleeping for 3 seconds...)");
@ -250,15 +251,18 @@ SYMBOL_INTERNAL void* ScreenshotThread(void* arg) {
return NULL; return NULL;
} }
SYMBOL_INTERNAL void GamestateProgress(struct Game* game) { SYMBOL_INTERNAL void CalculateProgress(struct Game* game) {
struct Gamestate* tmp = game->_priv.loading.current; struct Gamestate* tmp = game->_priv.loading.current;
game->_priv.loading.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);
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;
if (game->config.debug) { 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 #ifndef LIBSUPERDERPY_SINGLE_THREAD
// TODO: debounce thread synchronization to reduce overhead // TODO: debounce thread synchronization to reduce overhead
al_lock_mutex(game->_priv.texture_sync_mutex); 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_Draw = dlsym(gamestate->handle, "Gamestate_Draw"))) { GS_ERROR; }
if (!(gamestate->api->Gamestate_Logic = dlsym(gamestate->handle, "Gamestate_Logic"))) { 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_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_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_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 #undef GS_ERROR
@ -340,6 +347,7 @@ SYMBOL_INTERNAL struct Gamestate* AllocateGamestate(struct Game* game, const cha
tmp->pending_unload = false; tmp->pending_unload = false;
tmp->next = NULL; tmp->next = NULL;
tmp->api = NULL; tmp->api = NULL;
tmp->progressCount = 0;
return tmp; return tmp;
} }
@ -541,7 +549,9 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) {
CloseGamestate(game, tmp); CloseGamestate(game, tmp);
tmp->name = name; tmp->name = name;
if (OpenGamestate(game, tmp) && LinkGamestate(game, tmp)) { 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; tmp = tmp->next;
} }

View file

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

View file

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