initial support of run-time loading gamestates as dynamic libraries

This commit is contained in:
Sebastian Krzyszkowiak 2012-12-26 02:25:56 +01:00
parent b36c5e8ed4
commit 232cc6a204
10 changed files with 174 additions and 71 deletions

View file

@ -37,16 +37,20 @@ else(APPLE)
endif(APPLE)
add_library("libsuperderpy" SHARED ${SRC_LIST})
add_library("libsuperderpy-muffinattack-disclaimer" SHARED "gamestates/disclaimer.c")
add_executable(${EXECUTABLE} WIN32 MACOSX_BUNDLE "main.c")
SET_TARGET_PROPERTIES("libsuperderpy" PROPERTIES PREFIX "")
SET_TARGET_PROPERTIES("libsuperderpy-muffinattack-disclaimer" PROPERTIES PREFIX "")
include_directories(${ALLEGRO5_INCLUDE_DIR} ${ALLEGRO5_FONT_INCLUDE_DIR} ${ALLEGRO5_TTF_INCLUDE_DIR} ${ALLEGRO5_PRIMITIVES_INCLUDE_DIR} ${ALLEGRO5_AUDIO_INCLUDE_DIR} ${ALLEGRO5_ACODEC_INCLUDE_DIR} ${ALLEGRO5_IMAGE_INCLUDE_DIR})
target_link_libraries(${EXECUTABLE} ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m libsuperderpy)
target_link_libraries(${EXECUTABLE} ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m dl libsuperderpy)
target_link_libraries("libsuperderpy" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m)
target_link_libraries("libsuperderpy-muffinattack-disclaimer" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m libsuperderpy)
if(ALLEGRO5_MAIN_FOUND)
target_link_libraries(${EXECUTABLE} ${ALLEGRO5_MAIN_LIBRARIES})

View file

@ -23,10 +23,10 @@
#include "gamestate.h"
struct Gamestate* AddNewGamestate(struct Game *game) {
struct Gamestate *tmp = game->_priv.gamestate_list;
struct Gamestate *tmp = game->_priv.gamestates;
if (!tmp) {
game->_priv.gamestate_list = malloc(sizeof(struct Gamestate));
tmp = game->_priv.gamestate_list;
game->_priv.gamestates = malloc(sizeof(struct Gamestate));
tmp = game->_priv.gamestates;
} else {
while (tmp->next) {
tmp = tmp->next;
@ -49,7 +49,7 @@ struct Gamestate* AddNewGamestate(struct Game *game) {
}
struct Gamestate* FindGamestate(struct Game *game, const char* name) {
struct Gamestate *tmp = game->_priv.gamestate_list;
struct Gamestate *tmp = game->_priv.gamestates;
while (tmp) {
if (!strcmp(name, tmp->name)) {
return tmp;

View file

@ -21,6 +21,8 @@
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include "allegro5/allegro.h"
struct Game;
struct Gamestate {
@ -29,10 +31,27 @@ struct Gamestate {
bool loaded, pending_load;
bool started, pending_start;
bool paused;
bool fade;
bool fade; // TODO: or maybe should it be in API?
unsigned char fade_counter;
char** after;
char** after; // TODO: and this one too?
struct Gamestate* next;
struct {
void (*Gamestate_Draw)(struct Game *game);
void (*Gamestate_Logic)(struct Game *game);
void (*Gamestate_Load)(struct Game *game, void (*progress)(struct Game *game));
void (*Gamestate_Start)(struct Game *game);
void (*Gamestate_Pause)(struct Game *game);
void (*Gamestate_Resume)(struct Game *game);
void (*Gamestate_Stop)(struct Game *game);
void (*Gamestate_Unload)(struct Game *game);
void (*Gamestate_ProcessEvent)(struct Game *game, ALLEGRO_EVENT *ev);
void (*Gamestate_Keydown)(struct Game *game, ALLEGRO_EVENT *ev); // TODO: rly?
void (*Gamestate_Reload)(struct Game *game);
int *Gamestate_ProgressCount;
} api;
};
void LoadGamestate(struct Game *game, const char* name);

View file

@ -18,44 +18,58 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include "intro.h"
#include "menu.h"
#include "about.h"
//#include <stdio.h>
#include "../utils.h"
void Disclaimer_Draw(struct Game *game) {
struct {
ALLEGRO_FONT *font, *font_small;
} res;
// FIXME: bad bad bad bad!
void Gamestate_Logic(struct Game *game) {
}
void Gamestate_Draw(struct Game *game) {
al_clear_to_color(al_map_rgb(0,0,0));
al_draw_text_with_shadow(game->menu.font_selected, al_map_rgb(255,255,255), game->viewportWidth/2, game->viewportHeight*0.3, ALLEGRO_ALIGN_CENTRE, "This is an early development preview of the game.");
al_draw_text_with_shadow(game->menu.font_selected, al_map_rgb(255,255,255), game->viewportWidth/2, game->viewportHeight*0.4, ALLEGRO_ALIGN_CENTRE, "It's not supposed to be complete!");
al_draw_text_with_shadow(game->menu.font_selected, al_map_rgb(255,255,255), game->viewportWidth/2, game->viewportHeight*0.5, ALLEGRO_ALIGN_CENTRE, "Keep in mind that everything may be changed");
al_draw_text_with_shadow(game->menu.font_selected, al_map_rgb(255,255,255), game->viewportWidth/2, game->viewportHeight*0.6, ALLEGRO_ALIGN_CENTRE, "and many things surely will change.");
al_draw_text_with_shadow(game->menu.font, al_map_rgb(255,255,255), game->viewportWidth/2, game->viewportHeight*0.9, ALLEGRO_ALIGN_CENTRE, "Press any key to continue...");
DrawTextWithShadow(res.font, al_map_rgb(255,255,255), game->viewport.width/2, game->viewport.height*0.3, ALLEGRO_ALIGN_CENTRE, "This is an early development preview of the game.");
DrawTextWithShadow(res.font, al_map_rgb(255,255,255), game->viewport.width/2, game->viewport.height*0.4, ALLEGRO_ALIGN_CENTRE, "It's not supposed to be complete!");
DrawTextWithShadow(res.font, al_map_rgb(255,255,255), game->viewport.width/2, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Keep in mind that everything may be changed");
DrawTextWithShadow(res.font, al_map_rgb(255,255,255), game->viewport.width/2, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "and many things surely will change.");
DrawTextWithShadow(res.font_small, al_map_rgb(255,255,255), game->viewport.width/2, game->viewport.height*0.9, ALLEGRO_ALIGN_CENTRE, "Press any key to continue...");
}
void Disclaimer_Load(struct Game *game) {
FadeGameState(game, true);
void Gamestate_Start(struct Game *game) {
FadeGamestate(game, true);
}
int Disclaimer_Keydown(struct Game *game, ALLEGRO_EVENT *ev) {
UnloadGameState(game);
game->loadstate = GAMESTATE_INTRO;
LoadGameState(game);
int Gamestate_Keydown(struct Game *game, ALLEGRO_EVENT *ev) {
StopGamestate(game, "disclaimer");
UnloadGamestate(game, "disclaimer");
LoadGamestate(game, "intro");
StartGamestate(game, "intro");
return 0;
}
void Disclaimer_Preload(struct Game *game, void (*progress)(struct Game*, float)) {
if (!game->menu.loaded) {
game->menu.font = al_load_ttf_font(GetDataFilePath("fonts/ShadowsIntoLight.ttf"),game->viewportHeight*0.05,0 );
game->menu.font_selected = al_load_ttf_font(GetDataFilePath("fonts/ShadowsIntoLight.ttf"),game->viewportHeight*0.065,0 );
}
PrintConsole(game, "Preloading GAMESTATE_INTRO...");
Intro_Preload(game, progress);
void Gamestate_Load(struct Game *game, void (*progress)(struct Game*)) {
res.font_small = al_load_ttf_font(GetDataFilePath("fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.05,0 );
res.font = al_load_ttf_font(GetDataFilePath("fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.065,0 );
//PrintConsole(game, "Preloading GAMESTATE_INTRO...");
//Intro_Preload(game, progress);
}
void Disclaimer_Unload(struct Game *game) {
FadeGameState(game, false);
if (!game->menu.loaded) {
al_destroy_font(game->menu.font);
al_destroy_font(game->menu.font_selected);
}
void Gamestate_Stop(struct Game *game) {
FadeGamestate(game, false);
}
void Gamestate_Unload(struct Game *game) {
al_destroy_font(res.font);
al_destroy_font(res.font_small);
}
void Gamestate_Reload(struct Game *game) {}
void Gamestate_Resume(struct Game *game) {}
void Gamestate_Pause(struct Game *game) {}
void Gamestate_ProcessEvent(struct Game *game, ALLEGRO_EVENT *ev) {}
int Gamestate_ProgressCount = 0;

View file

@ -18,10 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "../main.h"
void Disclaimer_Draw(struct Game *game);
void Disclaimer_Preload(struct Game *game, void (*progress)(struct Game*, float));
void Disclaimer_Unload(struct Game *game);
void Disclaimer_Load(struct Game *game);
int Disclaimer_Keydown(struct Game *game, ALLEGRO_EVENT *ev);
void Gamestate_Draw(struct Game *game);
void Gamestate_Preload(struct Game *game, void (*progress)(struct Game*, float));
void Gamestate_Unload(struct Game *game);
void Gamestate_Load(struct Game *game);
int Gamestate_Keydown(struct Game *game, ALLEGRO_EVENT *ev);

View file

@ -27,6 +27,7 @@
#include <getopt.h>
#include <locale.h>
#include <signal.h>
#include <dlfcn.h>
#include "utils.h"
#include "config.h"
#include "main.h"
@ -51,31 +52,53 @@ void DrawConsole(struct Game *game) {
int counter=0;
void DrawGamestates(struct Game *game) {
if (counter<0) {
/*if (counter<0) {
PrintConsole(game, "logiced %d", abs(counter));
counter=0;
}
counter++;
counter++;*/
al_clear_to_color(al_map_rgb(0,0,0));
struct Gamestate *tmp = game->_priv.gamestate_list;
struct Gamestate *tmp = game->_priv.gamestates;
while (tmp) {
if ((tmp->loaded) && (tmp->started)) {
//PrintConsole(game, "drawing %s", tmp->name);
(*tmp->api.Gamestate_Draw)(game);
}
tmp = tmp->next;
}
}
void LogicGamestates(struct Game *game) {
if (counter>0) {
/*if (counter>0) {
PrintConsole(game, "drawed %d", abs(counter));
counter=0;
}
counter--;
struct Gamestate *tmp = game->_priv.gamestate_list;
counter--;*/
struct Gamestate *tmp = game->_priv.gamestates;
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
//PrintConsole(game, "logic %s", tmp->name);
(*tmp->api.Gamestate_Logic)(game);
}
tmp = tmp->next;
}
}
void KeydownGamestates(struct Game *game, ALLEGRO_EVENT *ev) {
struct Gamestate *tmp = game->_priv.gamestates;
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
(*tmp->api.Gamestate_Keydown)(game, ev);
}
tmp = tmp->next;
}
}
void EventGamestates(struct Game *game, ALLEGRO_EVENT *ev) {
struct Gamestate *tmp = game->_priv.gamestates;
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
(*tmp->api.Gamestate_ProcessEvent)(game, ev);
}
tmp = tmp->next;
}
@ -238,8 +261,7 @@ int main(int argc, char **argv){
PrintConsole(&game, "Viewport %dx%d", game.viewport.width, game.viewport.height);
game._priv.gamestate = NULL;
game._priv.gamestate_list = NULL;
game._priv.gamestates = NULL;
game._priv.event_queue = al_create_event_queue();
if(!game._priv.event_queue) {
@ -282,7 +304,7 @@ int main(int argc, char **argv){
game.shuttingdown = false;
game.restart = false;
char* gamestate = strdup("menu"); // FIXME: don't hardcore gamestate
char* gamestate = strdup("disclaimer"); // FIXME: don't hardcore gamestate
int c;
while ((c = getopt (argc, argv, "l:s:")) != -1)
@ -308,25 +330,69 @@ int main(int argc, char **argv){
ALLEGRO_EVENT ev;
if (redraw && al_is_event_queue_empty(game._priv.event_queue)) {
struct Gamestate *tmp = game._priv.gamestate_list;
struct Gamestate *tmp = game._priv.gamestates;
while (tmp) {
if ((tmp->pending_load) && (!tmp->loaded)) {
PrintConsole(&game, "Loading gamestate %s...", tmp->name);
tmp->loaded = true;
tmp->pending_load = false;
} else if ((tmp->pending_load) && (tmp->loaded)) {
// TODO: take proper game name
char libname[1024];
sprintf(libname, "libsuperderpy-%s-%s.so", "muffinattack", tmp->name);
tmp->handle = dlopen(libname,RTLD_NOW);
if (!tmp->handle) {
PrintConsole(&game, "Error while loading gamestate %s: %s", tmp->name, dlerror());
tmp->pending_load = false;
} else {
void gs_error() {
PrintConsole(&game, "Error on resolving gamestate symbol: %s", dlerror());
tmp->pending_load = false;
tmp=tmp->next;
}
if (!(tmp->api.Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Logic = dlsym(tmp->handle, "Gamestate_Logic"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Load = dlsym(tmp->handle, "Gamestate_Load"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Unload = dlsym(tmp->handle, "Gamestate_Unload"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Keydown = dlsym(tmp->handle, "Gamestate_Keydown"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { gs_error(); continue; }
if (!(tmp->api.Gamestate_ProgressCount = dlsym(tmp->handle, "Gamestate_ProgressCount"))) { gs_error(); continue; }
(*tmp->api.Gamestate_Load)(&game, NULL);
tmp->loaded = true;
tmp->pending_load = false;
}
} else if ((tmp->pending_start) && (tmp->started)) {
PrintConsole(&game, "Stopping gamestate %s...", tmp->name);
(*tmp->api.Gamestate_Stop)(&game);
tmp->started = false;
tmp->pending_start = false;
}
else if ((tmp->pending_load) && (tmp->loaded)) {
PrintConsole(&game, "Unloading gamestate %s...", tmp->name);
tmp->loaded = false;
tmp->pending_load = false;
(*tmp->api.Gamestate_Unload)(&game);
dlclose(tmp->handle);
tmp->handle = NULL;
} else if ((tmp->pending_start) && (!tmp->started)) {
PrintConsole(&game, "Starting gamestate %s...", tmp->name);
tmp->started = true;
tmp->pending_start = false;
} else if ((tmp->pending_start) && (tmp->started)) {
PrintConsole(&game, "Stopping gamestate %s...", tmp->name);
tmp->started = false;
tmp->pending_start = false;
if (!tmp->loaded) {
PrintConsole(&game, "Tried to start not loaded gamestate %s!", tmp->name);
tmp->pending_start = false;
} else {
PrintConsole(&game, "Starting gamestate %s...", tmp->name);
(*tmp->api.Gamestate_Start)(&game);
tmp->started = true;
tmp->pending_start = false;
}
}
tmp=tmp->next;
}
@ -386,12 +452,11 @@ int main(int argc, char **argv){
PrintConsole(&game, "Screenshot stored in %s", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP));
al_destroy_path(path);
} else if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
// TODO: handle shutting down with gamestates correctly (unloading last gamestate)
break;
}
// TODO: redirect keydown events to gamestates
//KEYDOWN_STATE(GAMESTATE_MENU, Menu)
//KEYDOWN_STATE(GAMESTATE_LOADING, Loading)
KeydownGamestates(&game, &ev);
/*else {
game._priv.showconsole = true;
//PrintConsole(&game, "ERROR: Keystroke in unknown (%d) gamestate! (5 sec sleep)", game.gamestate);
@ -402,7 +467,8 @@ int main(int argc, char **argv){
//game.gamestate = GAMESTATE_LOADING;
//game.loadstate = GAMESTATE_MENU;
}*/
//} else if (game.gamestate == GAMESTATE_LEVEL) {
} else {
EventGamestates(&game, &ev);
//Level_ProcessEvent(&game, &ev);
}
}
@ -429,9 +495,9 @@ int main(int argc, char **argv){
al_destroy_voice(game.audio.v);
al_uninstall_audio();
DeinitConfig(&game);
al_uninstall_system();
al_shutdown_ttf_addon();
al_shutdown_font_addon();
al_uninstall_system();
if (game.restart) {
#ifdef ALLEGRO_MACOSX
return _al_mangled_main(argc, argv);

View file

@ -62,8 +62,8 @@ struct Game {
} audio; /*!< Audio resources. */
struct {
struct Gamestate *gamestate; /*!< Current gamestate. */
struct Gamestate *gamestate_list; /*!< List of known gamestates. */
//struct Gamestate *gamestate; /*!< Current gamestate. */
struct Gamestate *gamestates; /*!< List of known gamestates. */
ALLEGRO_FONT *font; /*!< Main font used in game. */
ALLEGRO_FONT *font_console; /*!< Font used in game console. */
ALLEGRO_BITMAP *console; /*!< Bitmap with game console. */

View file

@ -22,6 +22,7 @@
#include "utils.h"
#include "timeline.h"
// FIXME: pack into Timeline structure
unsigned int lastid;
struct Game* game = NULL;
struct TM_Action *queue, *background;

View file

@ -209,7 +209,7 @@ char* GetDataFilePath(char* filename) {
void PrintConsole(struct Game *game, char* format, ...) {
va_list vl;
va_start(vl, format);
char text[255] = {};
char text[1024] = {};
vsprintf(text, format, vl);
va_end(vl);
if (game->config.debug) { printf("%s\n", text); fflush(stdout); }

View file

@ -38,7 +38,7 @@ void DrawTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float
ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, int height);
/*! \brief Displays fade in or fade out animation on current gamestate. */
void FadeGameState(struct Game *game, bool in);
void FadeGamestate(struct Game *game, bool in);
/*! \brief Finds path for data file. */
char* GetDataFilePath(char* filename);