# HG changeset patch # User Medo # Date 1339205318 -7200 # Node ID f84805e6df0331da000ba728bd742125be3fcc13 # Parent bf6cf4dd847a03cee507de4d3d803b4ea80ea40d Implemented game launching API for the frontlib. It is still buggy though, and not all game settings can be conveniently created/modified yet. diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/buffer.c --- a/project_files/frontlib/buffer.c Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#include "buffer.h" -#include "logging.h" - -#include -#include -#include - -typedef struct _flib_vector { - void *data; - size_t size; - size_t capacity; -} _flib_vector; - -flib_vector flib_vector_create() { - flib_vector result = malloc(sizeof(_flib_vector)); - if(result == NULL) { - return NULL; - } - result->data = malloc(16); - if(result->data == NULL) { - free(result); - return NULL; - } - result->size = 0; - result->capacity = 16; - return result; -} - -void flib_vector_destroy(flib_vector *vec) { - if(vec && *vec) { - free((*vec)->data); - free(*vec); - *vec = NULL; - } -} - -static void try_realloc(flib_vector vec, size_t newCapacity) { - void *newData = realloc(vec->data, newCapacity); - if(newData) { - vec->data = newData; - vec->capacity = newCapacity; - } -} - -static size_t getFreeCapacity(flib_vector vec) { - return vec->capacity - vec->size; -} - -int flib_vector_append(flib_vector vec, const void *data, size_t len) { - if(getFreeCapacity(vec) < len) { - // Resize exponentially for constant amortized time, - // But at least by as much as we need of course, - // and be extra careful with integer overflows... - size_t extraCapacity = (vec->capacity)/2; - - size_t minExtraCapacity = len - getFreeCapacity(vec); - if(extraCapacity < minExtraCapacity) { - extraCapacity = minExtraCapacity; - } - - if(extraCapacity <= SIZE_MAX - vec->capacity) { - try_realloc(vec, vec->capacity+extraCapacity); - } - - // Check if we were able to resize. - // If not, try to allocate at least what we need... - if(getFreeCapacity(vec) < len) { - try_realloc(vec, vec->capacity+minExtraCapacity); - - // Still not working? Then we fail. - if(getFreeCapacity(vec) < len) { - return 0; - } - } - } - - memmove(vec->data + vec->size, data, len); - vec->size += len; - return len; -} - -flib_buffer flib_vector_as_buffer(flib_vector vec) { - flib_buffer result = {vec->data, vec->size}; - return result; -} - -flib_constbuffer flib_vector_as_constbuffer(flib_vector vec) { - flib_constbuffer result = {vec->data, vec->size}; - return result; -} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/buffer.h --- a/project_files/frontlib/buffer.h Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -#ifndef BUFFER_H_ -#define BUFFER_H_ - -#include -#include - -/** - * A simple struct to hold both the pointer to an array and its size, - * for e.g. conveniently returning it from a function. - * - * Convention: Size is zero iff data is a NULL pointer. - */ -typedef struct { - void *data; - size_t size; -} flib_buffer; - -/** - * Just like flib_buffer, but the contents are not supposed to be modified. - */ -typedef struct { - const void *data; - size_t size; -} flib_constbuffer; - -/** - * Simple variable-capacity data structure (opaque type). - */ -struct _flib_vector; -typedef struct _flib_vector *flib_vector; - -/** - * Create a new vector. Needs to be destroyed again later with flib_vector_destroy. - * May return NULL if memory runs out. - */ -flib_vector flib_vector_create(); - -/** - * Free the memory of this vector and set it to NULL. - */ -void flib_vector_destroy(flib_vector *vec); - -/** - * Append the provided data to the end of the vector, enlarging it as required. - * Returns the ammount of data appended, which is either len (success) or 0 (out of memory). - * The vector remains unchanged if an out of memory situation occurs. - */ -int flib_vector_append(flib_vector vec, const void *data, size_t len); - -/** - * Return a buffer or constbuffer pointing to the current contents of the vector. - * These will become invalid if the vector size or capacity is changed. - */ -flib_buffer flib_vector_as_buffer(flib_vector vec); -flib_constbuffer flib_vector_as_constbuffer(flib_vector vec); - - -#endif diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/frontlib.c --- a/project_files/frontlib/frontlib.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/frontlib.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,8 +1,8 @@ #include "frontlib.h" -#include "logging.h" +#include "util/logging.h" #include "model/map.h" #include "ipc/mapconn.h" -#include "ipc.h" +#include "ipc/gameconn.h" #include #include @@ -41,97 +41,72 @@ } } -static void onConfigQuery(void *context) { - flib_log_i("Sending config..."); - flib_ipc ipc = (flib_ipc)context; - flib_ipc_send_messagestr(ipc, "TL"); - flib_ipc_send_messagestr(ipc, "eseed loremipsum"); - flib_ipc_send_messagestr(ipc, "e$mapgen 0"); - flib_ipc_send_messagestr(ipc, "e$template_filter 0"); - flib_ipc_send_messagestr(ipc, "etheme Jungle"); - flib_ipc_send_messagestr(ipc, "eaddteam 11111111111111111111111111111111 255 Medo42"); -} - -static void onDisconnect(void *context) { - flib_log_i("Connection closed."); - flib_ipc_destroy((flib_ipc*)context); -} - -static void onGameEnd(void *context, int gameEndType) { - switch(gameEndType) { - case GAME_END_FINISHED: - flib_log_i("Game finished."); - flib_constbuffer demobuf = flib_ipc_getdemo(context); - flib_log_i("Writing demo (%u bytes)...", (unsigned)demobuf.size); - FILE *file = fopen("testdemo.dem", "wb"); - fwrite(demobuf.data, 1, demobuf.size, file); - fclose(file); - file = NULL; - break; - case GAME_END_HALTED: - flib_log_i("Game halted."); - break; - case GAME_END_INTERRUPTED: - flib_log_i("Game iterrupted."); - break; - } -} - -static void handleMapSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) { - printf("Drawing map for %i brave little hogs...", numHedgehogs); - int pixelnum = 0; - for(int y=0; y>3] & (1<<(7-(pixelnum&7)))) { - printf("#"); - } else { - printf(" "); - } - pixelnum++; - } - printf("\n"); - } - - flib_mapconn **connptr = context; - flib_mapconn_destroy(*connptr); +static void onDisconnect(void *context, int reason) { + flib_log_i("Connection closed. Reason: %i", reason); + flib_gameconn **connptr = context; + flib_gameconn_destroy(*connptr); *connptr = NULL; } -static void handleMapFailure(void *context, const char *errormessage) { - flib_log_e("Map rendering failed: %s", errormessage); - - flib_mapconn **connptr = context; - flib_mapconn_destroy(*connptr); - *connptr = NULL; +static void onGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) { + flib_log_i("Writing %s (%i bytes)...", isSavegame ? "savegame" : "demo", size); + FILE *file = fopen(isSavegame ? "testsave.42.hws" : "testdemo.42.hwd", "wb"); + fwrite(record, 1, size, file); + fclose(file); } int main(int argc, char *argv[]) { -/* flib_init(0); - - flib_cfg_meta *meta = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini"); - flib_cfg *cfg = flib_cfg_create(meta, "DefaultScheme"); - flib_cfg_to_ini(meta, "defaulttest.ini", cfg); - - flib_cfg_meta_destroy(meta); - - flib_quit(); - return 0;*/ + flib_init(0); - flib_init(0); - flib_map *mapconf = flib_map_create_regular("Jungle", TEMPLATEFILTER_CAVERN); - assert(mapconf); - - flib_mapconn *mapconn = flib_mapconn_create("foobart", mapconf); - assert(mapconn); + flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini"); + assert(metaconf); + flib_gamesetup setup; + setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini"); + setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS); + setup.seed = "apsfooasdgnds"; + setup.teamcount = 2; + setup.teams = calloc(2, sizeof(flib_team)); + setup.teams[0].color = 0xffff0000; + setup.teams[0].flag = "australia"; + setup.teams[0].fort = "Plane"; + setup.teams[0].grave = "Bone"; + setup.teams[0].hogsInGame = 2; + setup.teams[0].name = "Team Awesome"; + setup.teams[0].voicepack = "British"; + setup.teams[0].weaponset = flib_weaponset_create("Defaultweaps"); + setup.teams[0].hogs[0].difficulty = 2; + setup.teams[0].hogs[0].hat = "NoHat"; + setup.teams[0].hogs[0].initialHealth = 100; + setup.teams[0].hogs[0].name = "Harry 120"; + setup.teams[0].hogs[1].difficulty = 2; + setup.teams[0].hogs[1].hat = "chef"; + setup.teams[0].hogs[1].initialHealth = 100; + setup.teams[0].hogs[1].name = "Chefkoch"; + setup.teams[1].color = 0xff0000ff; + setup.teams[1].flag = "germany"; + setup.teams[1].fort = "Cake"; + setup.teams[1].grave = "Cherry"; + setup.teams[1].hogsInGame = 2; + setup.teams[1].name = "The Krauts"; + setup.teams[1].voicepack = "Pirate"; + setup.teams[1].weaponset = flib_weaponset_create("Defaultweaps"); + setup.teams[1].hogs[0].difficulty = 0; + setup.teams[1].hogs[0].hat = "quotecap"; + setup.teams[1].hogs[0].initialHealth = 100; + setup.teams[1].hogs[0].name = "Quote"; + setup.teams[1].hogs[1].difficulty = 0; + setup.teams[1].hogs[1].hat = "chef"; + setup.teams[1].hogs[1].initialHealth = 100; + setup.teams[1].hogs[1].name = "Chefkoch2"; - flib_map_destroy(mapconf); - mapconf = NULL; + flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false); + assert(gameconn); - flib_mapconn_onFailure(mapconn, &handleMapFailure, &mapconn); - flib_mapconn_onSuccess(mapconn, &handleMapSuccess, &mapconn); + flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); + flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); - while(mapconn) { - flib_mapconn_tick(mapconn); + while(gameconn) { + flib_gameconn_tick(gameconn); } flib_log_i("Shutting down..."); flib_quit(); diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/hwconsts.h --- a/project_files/frontlib/hwconsts.h Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/hwconsts.h Sat Jun 09 03:28:38 2012 +0200 @@ -9,6 +9,8 @@ #define HEDGEHOGS_PER_TEAM 8 #define NETGAME_DEFAULT_PORT 46631 +#define GAMEMOD_PERHOGAMMO_MASKBIT 22 +#define GAMEMOD_SHAREDAMMO_MASKBIT 16 #define WEAPONS_COUNT 55 #define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111011" diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ini/inihelper.c --- a/project_files/frontlib/ini/inihelper.c Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -#include "inihelper.h" -#include "../logging.h" -#include "../util.h" - -#include -#include -#include -#include -#include -#include - -static bool keychar_needs_urlencoding(char c) { - return !isalnum(c); -} - -char *inihelper_urlencode(const char *inbuf) { - if(!inbuf) { - return NULL; - } - size_t insize = strlen(inbuf); - if(insize > SIZE_MAX/4) { - return NULL; - } - - char *outbuf = malloc(insize*3+1); - if(!outbuf) { - return NULL; - } - - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(!keychar_needs_urlencoding(inbuf[inpos])) { - outbuf[outpos++] = inbuf[inpos++]; - } else { - if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { - free(outbuf); - return NULL; - } - inpos++; - outpos += 3; - } - } - outbuf[outpos] = 0; - return outbuf; -} - -char *inihelper_urldecode(const char *inbuf) { - char *outbuf = malloc(strlen(inbuf)+1); - if(!outbuf) { - return NULL; - } - - size_t inpos = 0, outpos = 0; - while(inbuf[inpos]) { - if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { - char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; - outbuf[outpos++] = strtol(temp, NULL, 16); - inpos += 3; - } else { - outbuf[outpos++] = inbuf[inpos++]; - } - } - outbuf[outpos] = 0; - return outbuf; -} - -char *inihelper_createDictKey(const char *sectionName, const char *keyName) { - if(!sectionName || !keyName) { - return NULL; - } - return flib_asprintf("%s:%s", sectionName, keyName); -} - -char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - if(!inifile || !sectionName || !keyName) { - *error = true; - return NULL; - } - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(!extendedkey) { - *error = true; - return NULL; - } - char *result = iniparser_getstring(inifile, extendedkey, NULL); - free(extendedkey); - if(!result) { - flib_log_i("Missing ini setting: %s/%s", sectionName, keyName); - *error = true; - } - return result; -} - -char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - return flib_strdupnull(inihelper_getstring(inifile, error, sectionName, keyName)); -} - -int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return 0; - } else { - errno = 0; - long val = strtol(value, NULL, 10); - if(errno!=0) { - *error = true; - return 0; - } - if(valINT_MAX) { - *error = true; - return 0; - } - return (int)val; - } -} - -bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { - char *value = inihelper_getstring(inifile, error, sectionName, keyName); - if(!value) { - return false; - } else { - bool trueval = strchr("1tTyY", value[0]); - bool falseval = strchr("0fFnN", value[0]); - if(!trueval && !falseval) { - *error = true; - return false; - } else { - return trueval; - } - } -} - -int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) { - int result = -1; - if(!dict || !sectionName || !keyName || !value) { - flib_log_e("inihelper_setstr called with bad parameters"); - } else { - char *extendedkey = inihelper_createDictKey(sectionName, keyName); - if(extendedkey) { - result = iniparser_set(dict, extendedkey, value); - free(extendedkey); - } - } - return result; -} - -int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("inihelper_setint called with bad parameters"); - } else { - char *strvalue = flib_asprintf("%i", value); - if(strvalue) { - result = inihelper_setstr(dict, sectionName, keyName, strvalue); - free(strvalue); - } - } - return result; -} - -int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) { - int result = -1; - if(!dict || !sectionName || !keyName) { - flib_log_e("inihelper_setint called with bad parameters"); - } else { - result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false"); - } - return result; -} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ini/inihelper.h --- a/project_files/frontlib/ini/inihelper.h Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/** - * Some helper functions for working with the iniparser functions - in particular, - * for interoperability with the ini format used by the QtSettings class. - */ - -#ifndef INIHELPER_H_ -#define INIHELPER_H_ - -#include "../iniparser/iniparser.h" -#include - -/** - * Returned buffer must be free()d - */ -char *inihelper_urlencode(const char *inbuf); - -/** - * Returned buffer must be free()d - */ -char *inihelper_urldecode(const char *inbuf); - -/** - * Create a key in the format "sectionName:keyName" - * Returned buffer must be free()d - */ -char *inihelper_createDictKey(const char *sectionName, const char *keyName); - -/** - * Returns an internal buffer, don't modify or free - * Sets error to true if something goes wrong, leaves it unchanged otherwise. - */ -char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); - -/** - * Returned buffer must be free()d - * Sets error to true if something goes wrong, leaves it unchanged otherwise. - */ -char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); - -/** - * Sets error to true if something goes wrong, leaves it unchanged otherwise. - */ -int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); - -/** - * Sets error to true if something goes wrong, leaves it unchanged otherwise. - */ -bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); - -int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value); -int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value); -int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value); -#endif /* INIHELPER_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc.c --- a/project_files/frontlib/ipc.c Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -#include "ipc.h" -#include "ipc/ipcconn.h" -#include "logging.h" - -#include -#include - -typedef struct _flib_ipc { - flib_ipcconn connection; - IpcConnState oldConnState; - - void (*onConnectCb)(void*); - void *onConnectCtx; - - void (*onDisconnectCb)(void*); - void *onDisconnectCtx; - - void (*onConfigQueryCb)(void*); - void *onConfigQueryCtx; - - void (*onEngineErrorCb)(void*, const uint8_t*); - void *onEngineErrorCtx; - - void (*onGameEndCb)(void*, int); - void *onGameEndCtx; - - void (*onChatCb)(void*, const uint8_t*, int); - void *onChatCtx; - - void (*onEngineMessageCb)(void*, const uint8_t*, int); - void *onEngineMessageCtx; - - bool running; - bool destroyRequested; -} _flib_ipc; - -static void emptyCallback(void* ptr) {} -static void emptyCallback_int(void* ptr, int i) {} -static void emptyCallback_str(void* ptr, const uint8_t* str) {} -static void emptyCallback_str_int(void* ptr, const uint8_t* str, int i) {} - -static void clearCallbacks(flib_ipc ipc) { - ipc->onConnectCb = &emptyCallback; - ipc->onDisconnectCb = &emptyCallback; - ipc->onConfigQueryCb = &emptyCallback; - ipc->onEngineErrorCb = &emptyCallback_str; - ipc->onGameEndCb = &emptyCallback_int; - ipc->onChatCb = &emptyCallback_str_int; - ipc->onEngineMessageCb = &emptyCallback_str_int; -} - -flib_ipc flib_ipc_create(bool recordDemo, const char *localPlayerName) { - flib_ipc result = malloc(sizeof(_flib_ipc)); - flib_ipcconn connection = flib_ipcconn_create(recordDemo, localPlayerName); - - if(!result || !connection) { - free(result); - flib_ipcconn_destroy(&connection); - return NULL; - } - - result->connection = connection; - result->oldConnState = IPC_LISTENING; - result->running = false; - result->destroyRequested = false; - - clearCallbacks(result); - return result; -} - -void flib_ipc_destroy(flib_ipc *ipcptr) { - if(!ipcptr || !*ipcptr) { - return; - } - flib_ipc ipc = *ipcptr; - if(ipc->running) { - // The function was called from a callback of this ipc connection, - // so the tick function is still running and we delay the actual - // destruction. We ensure no further callbacks will be sent to prevent - // surprises. - clearCallbacks(ipc); - ipc->destroyRequested = true; - } else { - flib_ipcconn_destroy(&ipc->connection); - free(ipc); - } - *ipcptr = NULL; -} - -void flib_ipc_onConnect(flib_ipc ipc, void (*callback)(void* context), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onConnect with ipc==null"); - return; - } - ipc->onConnectCb = callback ? callback : &emptyCallback; - ipc->onConnectCtx = context; -} - -void flib_ipc_onDisconnect(flib_ipc ipc, void (*callback)(void* context), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onDisconnect with ipc==null"); - return; - } - ipc->onDisconnectCb = callback ? callback : &emptyCallback; - ipc->onDisconnectCtx = context; -} - -void flib_ipc_onConfigQuery(flib_ipc ipc, void (*callback)(void* context), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onConfigQuery with ipc==null"); - return; - } - ipc->onConfigQueryCb = callback ? callback : &emptyCallback; - ipc->onConfigQueryCtx = context; -} - -void flib_ipc_onEngineError(flib_ipc ipc, void (*callback)(void* context, const uint8_t *error), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onEngineError with ipc==null"); - return; - } - ipc->onEngineErrorCb = callback ? callback : &emptyCallback_str; - ipc->onEngineErrorCtx = context; -} - -void flib_ipc_onGameEnd(flib_ipc ipc, void (*callback)(void* context, int gameEndType), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onGameEnd with ipc==null"); - return; - } - ipc->onGameEndCb = callback ? callback : &emptyCallback_int; - ipc->onGameEndCtx = context; -} - -void flib_ipc_onChat(flib_ipc ipc, void (*callback)(void* context, const uint8_t *messagestr, int teamchat), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onChat with ipc==null"); - return; - } - ipc->onChatCb = callback ? callback : &emptyCallback_str_int; - ipc->onChatCtx = context; -} - -void flib_ipc_onEngineMessage(flib_ipc ipc, void (*callback)(void* context, const uint8_t *message, int len), void* context) { - if(!ipc) { - flib_log_w("Call to flib_ipc_onEngineMessage with ipc==null"); - return; - } - ipc->onEngineMessageCb = callback ? callback : &emptyCallback_str_int; - ipc->onEngineMessageCtx = context; -} - -static void flib_ipc_wrappedtick(flib_ipc ipc) { - if(ipc->oldConnState == IPC_NOT_CONNECTED) { - return; - } - - if(ipc->oldConnState == IPC_LISTENING) { - flib_ipcconn_accept(ipc->connection); - if(flib_ipcconn_state(ipc->connection) == IPC_CONNECTED) { - ipc->oldConnState = IPC_CONNECTED; - ipc->onConnectCb(ipc->onConnectCtx); - } - } - - if(ipc->oldConnState == IPC_CONNECTED) { - uint8_t msgbuffer[257]; - int len; - while(!ipc->destroyRequested && (len = flib_ipcconn_recv_message(ipc->connection, msgbuffer))>=0) { - if(len<2) { - flib_log_w("Received short message from IPC (<2 bytes)"); - continue; - } - msgbuffer[len] = 0; - flib_log_i("[IPC in] %s", msgbuffer+1); - switch(msgbuffer[1]) { - case '?': - flib_ipcconn_send_messagestr(ipc->connection, "!"); - break; - case 'C': - ipc->onConfigQueryCb(ipc->onConfigQueryCtx); - break; - case 'E': - if(len>=3) { - msgbuffer[len-2] = 0; - ipc->onEngineErrorCb(ipc->onEngineErrorCtx, msgbuffer+2); - } - break; - case 'i': - // TODO - break; - case 'Q': - ipc->onGameEndCb(ipc->onGameEndCtx, GAME_END_INTERRUPTED); - break; - case 'q': - ipc->onGameEndCb(ipc->onGameEndCtx, GAME_END_FINISHED); - break; - case 'H': - ipc->onGameEndCb(ipc->onGameEndCtx, GAME_END_HALTED); - break; - case 's': - if(len>=3) { - msgbuffer[len-2] = 0; - ipc->onChatCb(ipc->onChatCtx, msgbuffer+2, 0); - } - break; - case 'b': - if(len>=3) { - msgbuffer[len-2] = 0; - ipc->onChatCb(ipc->onChatCtx, msgbuffer+2, 1); - } - break; - default: - ipc->onEngineMessageCb(ipc->onEngineMessageCtx, msgbuffer, len); - break; - } - } - } - - if(flib_ipcconn_state(ipc->connection) == IPC_NOT_CONNECTED) { - ipc->oldConnState = IPC_NOT_CONNECTED; - ipc->onDisconnectCb(ipc->onDisconnectCtx); - } -} - -void flib_ipc_tick(flib_ipc ipc) { - if(!ipc) { - flib_log_w("Call to flib_ipc_tick with ipc==null"); - return; - } - if(ipc->running) { - flib_log_w("Call to flib_ipc_tick from a callback"); - return; - } - - ipc->running = true; - flib_ipc_wrappedtick(ipc); - ipc->running = false; - - if(ipc->destroyRequested) { - flib_ipc_destroy(&ipc); - } -} - -int flib_ipc_send_raw(flib_ipc ipc, void *data, size_t len) { - if(!ipc) { - flib_log_w("Call to flib_ipc_send_raw with ipc==null"); - return -1; - } - return flib_ipcconn_send_raw(ipc->connection, data, len); -} - -int flib_ipc_send_message(flib_ipc ipc, void *data, size_t len) { - if(!ipc) { - flib_log_w("Call to flib_ipc_send_message with ipc==null"); - return -1; - } - return flib_ipcconn_send_message(ipc->connection, data, len); -} - -int flib_ipc_send_messagestr(flib_ipc ipc, char *data) { - if(!ipc) { - flib_log_w("Call to flib_ipc_send_messagestr with ipc==null"); - return -1; - } - return flib_ipcconn_send_messagestr(ipc->connection, data); -} - -uint16_t flib_ipc_port(flib_ipc ipc) { - if(!ipc) { - flib_log_w("Call to flib_ipc_send_messagestr with ipc==null"); - return 0; - } - return flib_ipcconn_port(ipc->connection); -} - -flib_constbuffer flib_ipc_getdemo(flib_ipc ipc) { - if(!ipc) { - flib_log_w("Call to flib_ipc_send_messagestr with ipc==null"); - flib_constbuffer result = {NULL, 0}; - return result; - } - return flib_ipcconn_getrecord(ipc->connection, false); -} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc.h --- a/project_files/frontlib/ipc.h Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#ifndef IPC_H_ -#define IPC_H_ - -#include "buffer.h" -#include "model/weapon.h" - -#include -#include -#include - -struct _flib_ipc; -typedef struct _flib_ipc *flib_ipc; - -typedef enum { - GAME_END_FINISHED, - GAME_END_INTERRUPTED, - GAME_END_HALTED -} flib_GameEndType; - -flib_ipc flib_ipc_create(bool recordDemo, const char *localPlayerName); -void flib_ipc_destroy(flib_ipc *ipcptr); - -void flib_ipc_onConnect(flib_ipc ipc, void (*callback)(void* context), void* context); -void flib_ipc_onDisconnect(flib_ipc ipc, void (*callback)(void* context), void* context); -void flib_ipc_onConfigQuery(flib_ipc ipc, void (*callback)(void* context), void* context); -void flib_ipc_onEngineError(flib_ipc ipc, void (*callback)(void* context, const uint8_t *error), void* context); -void flib_ipc_onGameEnd(flib_ipc ipc, void (*callback)(void* context, int gameEndType), void* context); -void flib_ipc_onChat(flib_ipc ipc, void (*callback)(void* context, const uint8_t *messagestr, int teamchat), void* context); -void flib_ipc_onEngineMessage(flib_ipc ipc, void (*callback)(void* context, const uint8_t *message, int len), void* context); - -int flib_ipc_send_raw(flib_ipc ipc, void *data, size_t len); -int flib_ipc_send_message(flib_ipc ipc, void *data, size_t len); -int flib_ipc_send_messagestr(flib_ipc ipc, char *data); - -// Configuration -int flib_ipc_send_seed(flib_ipc ipc, const char *seed); -int flib_ipc_send_script(flib_ipc ipc, const char *scriptpath); -int flib_ipc_send_map_regular(flib_ipc ipc, const char *theme, int templateFilter); -int flib_ipc_send_map_maze(flib_ipc ipc, const char *theme, int mazeType); -int flib_ipc_send_map_drawn(flib_ipc ipc, const char *theme, void *drawnMapData, size_t drawnMapDataLen); -int flib_ipc_send_map_named(flib_ipc ipc, const char *mappath); -int flib_ipc_send_gamemods(flib_ipc ipc, uint32_t modflags); -int flib_ipc_send_gamesetting(flib_ipc ipc, const char *settingname, int modflags); -int flib_ipc_send_weaponset(flib_ipc ipc, flib_weaponset *set); - -int flib_ipc_send_conf_end(flib_ipc ipc); - - -uint16_t flib_ipc_port(flib_ipc ipc); -flib_constbuffer flib_ipc_getdemo(flib_ipc ipc); - -void flib_ipc_tick(flib_ipc ipc); - -#endif /* IPC_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/demo.c --- a/project_files/frontlib/ipc/demo.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/demo.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,5 +1,5 @@ #include "demo.h" -#include "../logging.h" +#include "../util/logging.h" #include #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/demo.h --- a/project_files/frontlib/ipc/demo.h Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/demo.h Sat Jun 09 03:28:38 2012 +0200 @@ -5,7 +5,7 @@ #ifndef DEMO_H_ #define DEMO_H_ -#include "../buffer.h" +#include "../util/buffer.h" /** * Record a message sent from the engine to the frontend. diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/gameconn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/ipc/gameconn.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,348 @@ +#include "gameconn.h" +#include "ipcconn.h" +#include "ipcprotocol.h" +#include "../util/logging.h" +#include "../hwconsts.h" +#include +#include + +typedef enum { + AWAIT_CONNECTION, + CONNECTED, + FINISHED +} gameconn_state; + +struct _flib_gameconn { + flib_ipcconn connection; + flib_vector configBuffer; + + gameconn_state state; + bool netgame; + + void (*onConnectCb)(void* context); + void *onConnectCtx; + + void (*onDisconnectCb)(void* context, int reason); + void *onDisconnectCtx; + + void (*onErrorMessageCb)(void* context, const char *msg); + void *onErrorMessageCtx; + + void (*onChatCb)(void* context, const char *msg, bool teamchat); + void *onChatCtx; + + void (*onGameRecordedCb)(void *context, const uint8_t *record, int size, bool isSavegame); + void *onGameRecordedCtx; + + void (*onNetMessageCb)(void *context, const uint8_t *em, int size); + void *onNetMessageCtx; + + bool running; + bool destroyRequested; +}; + +static void defaultCallback_onConnect(void* context) {} +static void defaultCallback_onDisconnect(void* context, int reason) {} +static void defaultCallback_onErrorMessage(void* context, const char *msg) { + flib_log_w("Error from engine (no callback set): %s", msg); +} +static void defaultCallback_onChat(void* context, const char *msg, bool teamchat) {} +static void defaultCallback_onGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) {} +static void defaultCallback_onNetMessage(void *context, const uint8_t *em, int size) {} + +static void clearCallbacks(flib_gameconn *conn) { + conn->onConnectCb = &defaultCallback_onConnect; + conn->onDisconnectCb = &defaultCallback_onDisconnect; + conn->onErrorMessageCb = &defaultCallback_onErrorMessage; + conn->onChatCb = &defaultCallback_onChat; + conn->onGameRecordedCb = &defaultCallback_onGameRecorded; + conn->onNetMessageCb = &defaultCallback_onNetMessage; +} + +static bool getGameMod(flib_cfg_meta *meta, flib_cfg *conf, int maskbit) { + for(int i=0; imodCount; i++) { + if(meta->mods[i].bitmaskIndex == maskbit) { + return conf->mods[i]; + } + } + flib_log_e("Unable to find game mod with mask bit %i", maskbit); + return false; +} + +static int fillConfigBuffer(flib_vector configBuffer, const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) { + bool error = false; + bool perHogAmmo = false; + bool sharedAmmo = false; + + error |= flib_ipc_append_message(configBuffer, netgame ? "TN" : "TL"); + error |= flib_ipc_append_seed(configBuffer, setup->seed); + if(setup->map) { + error |= flib_ipc_append_mapconf(configBuffer, setup->map, false); + } + if(setup->script) { + error |= flib_ipc_append_message(configBuffer, "escript %s", setup->script); + } + if(setup->gamescheme) { + error |= flib_ipc_append_gamescheme(configBuffer, setup->gamescheme, metaconf); + perHogAmmo = getGameMod(metaconf, setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT); + sharedAmmo = getGameMod(metaconf, setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT); + } + if(setup->teams) { + for(int i=0; iteamcount; i++) { + error |= flib_ipc_append_addteam(configBuffer, &setup->teams[i], perHogAmmo, sharedAmmo); + } + } + error |= flib_ipc_append_message(configBuffer, "!"); + return error ? -1 : 0; +} + +static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) { + flib_gameconn *result = NULL; + flib_gameconn *tempConn = calloc(1, sizeof(flib_gameconn)); + if(tempConn) { + tempConn->connection = flib_ipcconn_create(record, playerName); + tempConn->configBuffer = flib_vector_create(); + if(tempConn->connection && tempConn->configBuffer) { + tempConn->state = AWAIT_CONNECTION; + tempConn->netgame = netGame; + clearCallbacks(tempConn); + result = tempConn; + tempConn = NULL; + } + } + flib_gameconn_destroy(tempConn); + return result; +} + +flib_gameconn *flib_gameconn_create(const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) { + flib_gameconn *result = NULL; + flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame); + if(tempConn) { + if(fillConfigBuffer(tempConn->configBuffer, playerName, metaconf, setup, netgame) == 0) { + result = tempConn; + tempConn = NULL; + } + } + flib_gameconn_destroy(tempConn); + return result; +} + +flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demo, int size) { + flib_gameconn *result = NULL; + flib_gameconn *tempConn = flib_gameconn_create_partial(false, "Player", false); + if(tempConn) { + if(flib_vector_append(tempConn->configBuffer, demo, size) == size) { + result = tempConn; + tempConn = NULL; + } + } + flib_gameconn_destroy(tempConn); + return result; +} + +flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *save, int size) { + flib_gameconn *result = NULL; + flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false); + if(tempConn) { + if(flib_vector_append(tempConn->configBuffer, save, size) == size) { + result = tempConn; + tempConn = NULL; + } + } + flib_gameconn_destroy(tempConn); + return result; +} + +void flib_gameconn_destroy(flib_gameconn *conn) { + if(conn) { + if(conn->running) { + /* + * The function was called from a callback, so the tick function is still running + * and we delay the actual destruction. We ensure no further callbacks will be + * sent to prevent surprises. + */ + clearCallbacks(conn); + conn->destroyRequested = true; + } else { + flib_ipcconn_destroy(&conn->connection); + flib_vector_destroy(&conn->configBuffer); + free(conn); + } + } +} + +int flib_gameconn_getport(flib_gameconn *conn) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_getport"); + return 0; + } else { + return flib_ipcconn_port(conn->connection); + } +} + +void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onConnect"); + } else { + conn->onConnectCb = callback ? callback : &defaultCallback_onConnect; + conn->onConnectCtx = context; + } +} + +void flib_gameconn_onDisconnect(flib_gameconn *conn, void (*callback)(void* context, int reason), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onDisconnect"); + } else { + conn->onDisconnectCb = callback ? callback : &defaultCallback_onDisconnect; + conn->onDisconnectCtx = context; + } +} + +void flib_gameconn_onErrorMessage(flib_gameconn *conn, void (*callback)(void* context, const char *msg), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onErrorMessage"); + } else { + conn->onErrorMessageCb = callback ? callback : &defaultCallback_onErrorMessage; + conn->onErrorMessageCtx = context; + } +} + +void flib_gameconn_onChat(flib_gameconn *conn, void (*callback)(void* context, const char *msg, bool teamchat), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onChat"); + } else { + conn->onChatCb = callback ? callback : &defaultCallback_onChat; + conn->onChatCtx = context; + } +} + +void flib_gameconn_onGameRecorded(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *record, int size, bool isSavegame), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onGameRecorded"); + } else { + conn->onGameRecordedCb = callback ? callback : &defaultCallback_onGameRecorded; + conn->onGameRecordedCtx = context; + } +} + +void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_onNetMessage"); + } else { + conn->onNetMessageCb = callback ? callback : &defaultCallback_onNetMessage; + conn->onNetMessageCtx = context; + } +} + +static void flib_gameconn_wrappedtick(flib_gameconn *conn) { + if(conn->state == AWAIT_CONNECTION) { + flib_ipcconn_accept(conn->connection); + switch(flib_ipcconn_state(conn->connection)) { + case IPC_CONNECTED: + { + flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer); + if(flib_ipcconn_send_raw(conn->connection, configBuffer.data, configBuffer.size)) { + conn->state = FINISHED; + conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR); + return; + } else { + conn->state = CONNECTED; + conn->onConnectCb(conn->onConnectCtx); + if(conn->destroyRequested) { + return; + } + } + } + break; + case IPC_NOT_CONNECTED: + conn->state = FINISHED; + conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR); + return; + default: + break; + } + } + + if(conn->state == CONNECTED) { + uint8_t msgbuffer[257]; + int len; + while(!conn->destroyRequested && (len = flib_ipcconn_recv_message(conn->connection, msgbuffer))>=0) { + if(len<2) { + flib_log_w("Received short message from IPC (<2 bytes)"); + continue; + } + switch(msgbuffer[1]) { + case '?': + // The pong is already part of the config message + break; + case 'C': + // And we already send the config message on connecting. + break; + case 'E': + if(len>=3) { + msgbuffer[len-2] = 0; + conn->onErrorMessageCb(conn->onErrorMessageCtx, (char*)msgbuffer+2); + } + break; + case 'i': + // TODO stats + break; + case 'Q': + case 'H': + case 'q': + { + int reason = msgbuffer[1]=='Q' ? GAME_END_INTERRUPTED : msgbuffer[1]=='H' ? GAME_END_HALTED : GAME_END_FINISHED; + bool savegame = (reason != GAME_END_FINISHED) && !conn->netgame; + flib_constbuffer record = flib_ipcconn_getrecord(conn->connection, savegame); + if(record.size) { + conn->onGameRecordedCb(conn->onGameRecordedCtx, record.data, record.size, savegame); + if(conn->destroyRequested) { + return; + } + } + conn->state = FINISHED; + conn->onDisconnectCb(conn->onDisconnectCtx, reason); + return; + } + case 's': + if(len>=3) { + msgbuffer[len-2] = 0; + conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, false); + } + break; + case 'b': + if(len>=3) { + msgbuffer[len-2] = 0; + conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, true); + } + break; + default: + conn->onNetMessageCb(conn->onNetMessageCtx, msgbuffer, len); + break; + } + } + } + + if(flib_ipcconn_state(conn->connection) == IPC_NOT_CONNECTED) { + conn->state = FINISHED; + conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR); + } +} + +void flib_gameconn_tick(flib_gameconn *conn) { + if(!conn) { + flib_log_e("null parameter in flib_gameconn_tick"); + } else if(conn->running) { + flib_log_w("Call to flib_gameconn_tick from a callback"); + } else if(conn->state == FINISHED) { + flib_log_w("Call to flib_gameconn_tick, but we are already done."); + } else { + conn->running = true; + flib_gameconn_wrappedtick(conn); + conn->running = false; + + if(conn->destroyRequested) { + flib_gameconn_destroy(conn); + } + } +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/gameconn.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/ipc/gameconn.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,81 @@ +#ifndef GAMECONN_H_ +#define GAMECONN_H_ + +#include "../util/buffer.h" +#include "../model/gamesetup.h" + +#include +#include +#include + +#define GAME_END_FINISHED 0 +#define GAME_END_INTERRUPTED 1 +#define GAME_END_HALTED 2 +#define GAME_END_ERROR 3 + +struct _flib_gameconn; +typedef struct _flib_gameconn flib_gameconn; + +flib_gameconn *flib_gameconn_create(const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame); +flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demo, int size); +flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *save, int size); +void flib_gameconn_destroy(flib_gameconn *conn); + +/** + * Returns the port on which the gameconn is listening. Only fails if you + * pass NULL (not allowed), in that case 0 is returned. + */ +int flib_gameconn_getport(flib_gameconn *conn); + +/** + * Perform I/O operations and call callbacks if something interesting happens. + * Should be called regularly. + */ +void flib_gameconn_tick(flib_gameconn *conn); + +// TODO: Not needed yet, only for netgames +/* +flib_gameconn_send_enginemsg(flib_gameconn conn, uint8_t *data, int len); +flib_gameconn_send_textmsg(flib_gameconn conn, int msgtype, const char *msg); +flib_gameconn_send_chatmsg(flib_gameconn conn, const char *playername, const char *msg); +*/ + +/** + * handleConnect(void *context) + */ +void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context); + +/** + * handleDisconnect(void *context, int reason) + */ +void flib_gameconn_onDisconnect(flib_gameconn *conn, void (*callback)(void* context, int reason), void* context); + +/** + * Receives error messages sent by the engine + * handleErrorMessage(void* context, const char *msg) + */ +void flib_gameconn_onErrorMessage(flib_gameconn *conn, void (*callback)(void* context, const char *msg), void* context); + +/** + * handleChat(void* context, const char *msg, bool teamchat) + */ +void flib_gameconn_onChat(flib_gameconn *conn, void (*callback)(void* context, const char *msg, bool teamchat), void* context); + +/** + * Called when the game ends + * handleGameRecorded(void *context, const uint8_t *record, int size, bool isSavegame) + */ +void flib_gameconn_onGameRecorded(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *record, int size, bool isSavegame), void* context); + +/** + * Called when the game ends + * TODO handleStats(???) + */ + +/** + * ...needs to be passed on to the server in a net game + * handleEngineMessage(void *context, const uint8_t *em, int size) + */ +void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context); + +#endif diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/ipcconn.c --- a/project_files/frontlib/ipc/ipcconn.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/ipcconn.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,7 +1,7 @@ #include "ipcconn.h" -#include "../logging.h" +#include "demo.h" +#include "../util/logging.h" #include "../socket.h" -#include "demo.h" #include #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/ipcconn.h --- a/project_files/frontlib/ipc/ipcconn.h Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/ipcconn.h Sat Jun 09 03:28:38 2012 +0200 @@ -5,7 +5,7 @@ #ifndef IPCCONN_H_ #define IPCCONN_H_ -#include "../buffer.h" +#include "../util/buffer.h" #include #include @@ -18,6 +18,8 @@ typedef struct _flib_ipcconn *flib_ipcconn; /** + * TODO move demo recording up by one layer? + * * Start an engine connection by listening on a random port. The selected port can * be queried with flib_ipcconn_port and has to be passed to the engine. * diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/ipcprotocol.c --- a/project_files/frontlib/ipc/ipcprotocol.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,10 +1,11 @@ #include "ipcprotocol.h" -#include "../util.h" -#include "../logging.h" +#include "../util/util.h" +#include "../util/logging.h" #include #include #include +#include int flib_ipc_append_message(flib_vector vec, const char *fmt, ...) { int result = -1; @@ -94,3 +95,87 @@ return flib_ipc_append_message(vec, "eseed %s", seed); } } + +int flib_ipc_append_gamescheme(flib_vector vec, flib_cfg *scheme, flib_cfg_meta *meta) { + int result = -1; + flib_vector tempvector = flib_vector_create(); + if(!vec || !scheme || !meta) { + flib_log_e("null parameter in flib_ipc_append_gamescheme"); + } else if(tempvector) { + bool error = false; + uint32_t gamemods = 0; + for(int i=0; imodCount; i++) { + if(scheme->mods[i]) { + gamemods |= (1<mods[i].bitmaskIndex); + } + } + error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, gamemods); + for(int i=0; isettingCount; i++) { + int value = scheme->settings[i]; + if(meta->settings[i].checkOverMax) { + value = value>meta->settings[i].max ? meta->settings[i].max : value; + } + if(meta->settings[i].times1000) { + value *= 1000; + } + error |= flib_ipc_append_message(tempvector, "%s %i", meta->settings[i].engineCommand, value); + } + + if(!error) { + // Message created, now we can copy everything. + flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); + if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { + result = 0; + } + } + } + flib_vector_destroy(&tempvector); + return result; +} + +// FIXME shared ammo will break per-team ammo +int flib_ipc_append_addteam(flib_vector vec, flib_team *team, bool perHogAmmo, bool sharedAmmo) { + int result = -1; + flib_vector tempvector = flib_vector_create(); + if(!vec || !team || !team->weaponset) { + flib_log_e("invalid parameter in flib_ipc_append_addteam"); + } else if(tempvector) { + bool error = false; + error |= flib_ipc_append_message(tempvector, "eammloadt %s", team->weaponset->loadout); + error |= flib_ipc_append_message(tempvector, "eammprob %s", team->weaponset->crateprob); + error |= flib_ipc_append_message(tempvector, "eammdelay %s", team->weaponset->delay); + error |= flib_ipc_append_message(tempvector, "eammreinf %s", team->weaponset->crateammo); + if(!perHogAmmo) { + error |= flib_ipc_append_message(tempvector, "eammstore"); + } + + char *hash = team->hash ? team->hash : "00000000000000000000000000000000"; + error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", hash, team->color, team->name); + + if(team->remoteDriven) { + error |= flib_ipc_append_message(tempvector, "erdriven"); + } + + error |= flib_ipc_append_message(tempvector, "egrave %s", team->grave); + error |= flib_ipc_append_message(tempvector, "efort %s", team->fort); + error |= flib_ipc_append_message(tempvector, "evoicepack %s", team->voicepack); + error |= flib_ipc_append_message(tempvector, "eflag %s", team->flag); + + // TODO bindings + + for(int i=0; ihogsInGame; i++) { + error |= flib_ipc_append_message(tempvector, "eaddhh %i %i %s", team->hogs[i].difficulty, team->hogs[i].initialHealth, team->hogs[i].name); + error |= flib_ipc_append_message(tempvector, "ehat %s", team->hogs[i].hat); + } + + if(!error) { + // Message created, now we can copy everything. + flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector); + if(flib_vector_append(vec, constbuf.data, constbuf.size) == constbuf.size) { + result = 0; + } + } + } + flib_vector_destroy(&tempvector); + return result; +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/ipcprotocol.h --- a/project_files/frontlib/ipc/ipcprotocol.h Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.h Sat Jun 09 03:28:38 2012 +0200 @@ -1,8 +1,10 @@ #ifndef IPCPROTOCOL_H_ #define IPCPROTOCOL_H_ -#include "../buffer.h" +#include "../util/buffer.h" #include "../model/map.h" +#include "../model/team.h" +#include "../model/cfg.h" #include @@ -35,4 +37,14 @@ */ int flib_ipc_append_seed(flib_vector vec, const char *seed); +/** + * Append the game scheme to the buffer. + * + * Returns nonzero if something goes wrong. In that case the buffer + * contents are unaffected. + */ +int flib_ipc_append_gamescheme(flib_vector vec, flib_cfg *seed, flib_cfg_meta *meta); + +int flib_ipc_append_addteam(flib_vector vec, flib_team *team, bool perHogAmmo, bool sharedAmmo); + #endif /* IPCPROTOCOL_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/mapconn.c --- a/project_files/frontlib/ipc/mapconn.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/mapconn.c Sat Jun 09 03:28:38 2012 +0200 @@ -2,8 +2,8 @@ #include "ipcconn.h" #include "ipcprotocol.h" -#include "../logging.h" -#include "../buffer.h" +#include "../util/logging.h" +#include "../util/buffer.h" #include @@ -11,14 +11,14 @@ AWAIT_CONNECTION, AWAIT_REPLY, FINISHED -} mapconn_progress; +} mapconn_state; struct _flib_mapconn { uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES]; flib_ipcconn connection; flib_vector configBuffer; - mapconn_progress progress; + mapconn_state progress; void (*onSuccessCb)(void*, const uint8_t*, int); void *onSuccessCtx; diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/ipc/mapconn.h --- a/project_files/frontlib/ipc/mapconn.h Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/ipc/mapconn.h Sat Jun 09 03:28:38 2012 +0200 @@ -2,6 +2,7 @@ #define IPC_MAPCONN_H_ #include "../model/map.h" + #include #define MAPIMAGE_WIDTH 256 diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/logging.c --- a/project_files/frontlib/logging.c Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -#include "logging.h" - -#include -#include -#include -#include - -char* flib_format_ip(uint32_t numip) { - static char ip[16]; - snprintf(ip, 16, "%u.%u.%u.%u", (unsigned)(numip>>24), (unsigned)((numip>>16)&0xff), (unsigned)((numip>>8)&0xff), (unsigned)(numip&0xff)); - return ip; -} - -static void log_time(FILE *file) { - time_t timer; - char buffer[25]; - struct tm* tm_info; - - time(&timer); - tm_info = localtime(&timer); - - strftime(buffer, 25, "%Y-%m-%d %H:%M:%S", tm_info); - fprintf(file, "%s", buffer); -} - -static void flib_vflog(FILE *file, const char *prefix, const char *fmt, va_list args) { - log_time(file); - fprintf(file, " [%s]", prefix); - vfprintf(file, fmt, args); - fprintf(file, "\n"); - fflush(file); -} - -void flib_log_e(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog(stderr, "E", fmt, argp); - va_end(argp); -} - -void flib_log_w(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog(stdout, "W", fmt, argp); - va_end(argp); -} - -void flib_log_i(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog(stdout, "I", fmt, argp); - va_end(argp); -} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/logging.h --- a/project_files/frontlib/logging.h Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -/* - * - */ - -#ifndef LOGGING_H_ -#define LOGGING_H_ - -#include - -char* flib_format_ip(uint32_t numip); - -void flib_log_e(const char *fmt, ...); -void flib_log_w(const char *fmt, ...); -void flib_log_i(const char *fmt, ...); - -#endif /* LOGGING_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/cfg.c --- a/project_files/frontlib/model/cfg.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/model/cfg.c Sat Jun 09 03:28:38 2012 +0200 @@ -2,9 +2,9 @@ #include "../iniparser/iniparser.h" #include "../iniparser/dictionary.h" -#include "../ini/inihelper.h" -#include "../logging.h" -#include "../util.h" +#include "../util/inihelper.h" +#include "../util/logging.h" +#include "../util/util.h" #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/gamesetup.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/gamesetup.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,2 @@ +#include "gamesetup.h" + diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/gamesetup.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/gamesetup.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,25 @@ +/** + * A complete game configuration that contains all settings for a + * local or networked game. + * + * It should be noted that the meta-configuration is not included. + */ + +#ifndef MODEL_GAMESETUP_H_ +#define MODEL_GAMESETUP_H_ + +#include "cfg.h" +#include "weapon.h" +#include "map.h" +#include "team.h" + +typedef struct { + char *seed; // required + char *script; // optional + flib_cfg *gamescheme; // optional + flib_map *map; // optional + flib_team *teams; // optional + int teamcount; +} flib_gamesetup; + +#endif diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/map.c --- a/project_files/frontlib/model/map.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/model/map.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,8 +1,8 @@ #include "map.h" -#include "../ini/inihelper.h" -#include "../util.h" -#include "../logging.h" +#include "../util/inihelper.h" +#include "../util/util.h" +#include "../util/logging.h" #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/team.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/team.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,1 @@ +#include "team.h" diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/team.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/team.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,51 @@ +#ifndef TEAM_H_ +#define TEAM_H_ + +#include "weapon.h" +#include "../hwconsts.h" + +#include +#include + +#define TEAM_DEFAULT_HOGNAME "Hog" +#define TEAM_DEFAULT_HAT "NoHat" +#define TEAM_DEFAULT_DIFFICULTY 0 +#define TEAM_DEFAULT_HEALTH 100 + +typedef struct { + char *name; + char *hat; + + // Statistics. They are irrelevant for the engine or server, + // but provided for ini reading/writing by the frontend. + int rounds; + int deaths; + int kills; + int suicides; + + // These settings are sometimes used on a per-team basis. + int difficulty; + int initialHealth; +} flib_hog; + +typedef struct { + flib_hog hogs[HEDGEHOGS_PER_TEAM]; + char *name; + char *grave; + char *fort; + char *voicepack; + char *flag; + + // TODO binds + + // Transient settings used in game setup + uint32_t color; + int hogsInGame; + bool remoteDriven; + char *hash; + + // This setting is sometimes used on a per-game basis. + flib_weaponset *weaponset; +} flib_team; + +#endif /* TEAM_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/model/weapon.c --- a/project_files/frontlib/model/weapon.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/model/weapon.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,9 +1,9 @@ #include "weapon.h" -#include "../ini/inihelper.h" #include "../iniparser/iniparser.h" -#include "../logging.h" -#include "../util.h" +#include "../util/inihelper.h" +#include "../util/logging.h" +#include "../util/util.h" #include #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/socket.c --- a/project_files/frontlib/socket.c Fri Jun 08 19:52:24 2012 +0200 +++ b/project_files/frontlib/socket.c Sat Jun 09 03:28:38 2012 +0200 @@ -1,5 +1,5 @@ #include "socket.h" -#include "logging.h" +#include "util/logging.h" #include #include #include diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util.c --- a/project_files/frontlib/util.c Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -#include "util.h" - -#include -#include -#include -#include -#include - -char *flib_asprintf(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - char *result = flib_vasprintf(fmt, argp); - va_end(argp); - return result; -} - -char *flib_vasprintf(const char *fmt, va_list args) { - char *result = NULL; - int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, - if(requiredSize>=0) { - char *tmpbuf = malloc(requiredSize); // allocate it - if(tmpbuf) { - if(vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. - result = tmpbuf; - tmpbuf = NULL; - } - } - free(tmpbuf); - } - return result; -} - -char *flib_strdupnull(const char *str) { - if(!str) { - return NULL; - } - return flib_asprintf("%s", str); -} - -void *flib_bufdupnull(const void *buf, size_t size) { - if(!buf || size==0) { - return NULL; - } - void *result = malloc(size); - if(result) { - memcpy(result, buf, size); - } - return result; -} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util.h --- a/project_files/frontlib/util.h Fri Jun 08 19:52:24 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -#ifndef FLIB_UTIL_H_ -#define FLIB_UTIL_H_ - -#include -#include - -/** - * Prints a format string to a newly allocated buffer of the required size. - * Parameters are like those for printf. Returns NULL on error. - * - * Returned buffer must be free()d - */ -char *flib_asprintf(const char *fmt, ...); - -/** - * Exactly as flib_asprintf, but accepts va_args. - */ -char *flib_vasprintf(const char *fmt, va_list args); - -/** - * Return a duplicate of the provided string, or NULL if an error - * occurs or if str is already NULL. - * - * Returned buffer must be free()d - */ -char *flib_strdupnull(const char *str); - -/** - * Return a duplicate of the provided buffer, or NULL if an error - * occurs or if buf is already NULL or if size is 0. - * - * Returned buffer must be free()d - */ -void *flib_bufdupnull(const void *buf, size_t size); - -#endif diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/buffer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/buffer.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,90 @@ +#include "buffer.h" +#include "logging.h" + +#include +#include +#include + +typedef struct _flib_vector { + void *data; + size_t size; + size_t capacity; +} _flib_vector; + +flib_vector flib_vector_create() { + flib_vector result = malloc(sizeof(_flib_vector)); + if(result == NULL) { + return NULL; + } + result->data = malloc(16); + if(result->data == NULL) { + free(result); + return NULL; + } + result->size = 0; + result->capacity = 16; + return result; +} + +void flib_vector_destroy(flib_vector *vec) { + if(vec && *vec) { + free((*vec)->data); + free(*vec); + *vec = NULL; + } +} + +static void try_realloc(flib_vector vec, size_t newCapacity) { + void *newData = realloc(vec->data, newCapacity); + if(newData) { + vec->data = newData; + vec->capacity = newCapacity; + } +} + +static size_t getFreeCapacity(flib_vector vec) { + return vec->capacity - vec->size; +} + +int flib_vector_append(flib_vector vec, const void *data, size_t len) { + if(getFreeCapacity(vec) < len) { + // Resize exponentially for constant amortized time, + // But at least by as much as we need of course, + // and be extra careful with integer overflows... + size_t extraCapacity = (vec->capacity)/2; + + size_t minExtraCapacity = len - getFreeCapacity(vec); + if(extraCapacity < minExtraCapacity) { + extraCapacity = minExtraCapacity; + } + + if(extraCapacity <= SIZE_MAX - vec->capacity) { + try_realloc(vec, vec->capacity+extraCapacity); + } + + // Check if we were able to resize. + // If not, try to allocate at least what we need... + if(getFreeCapacity(vec) < len) { + try_realloc(vec, vec->capacity+minExtraCapacity); + + // Still not working? Then we fail. + if(getFreeCapacity(vec) < len) { + return 0; + } + } + } + + memmove(vec->data + vec->size, data, len); + vec->size += len; + return len; +} + +flib_buffer flib_vector_as_buffer(flib_vector vec) { + flib_buffer result = {vec->data, vec->size}; + return result; +} + +flib_constbuffer flib_vector_as_constbuffer(flib_vector vec) { + flib_constbuffer result = {vec->data, vec->size}; + return result; +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/buffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/buffer.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,58 @@ +#ifndef BUFFER_H_ +#define BUFFER_H_ + +#include +#include + +/** + * A simple struct to hold both the pointer to an array and its size, + * for e.g. conveniently returning it from a function. + * + * Convention: Size is zero iff data is a NULL pointer. + */ +typedef struct { + void *data; + size_t size; +} flib_buffer; + +/** + * Just like flib_buffer, but the contents are not supposed to be modified. + */ +typedef struct { + const void *data; + size_t size; +} flib_constbuffer; + +/** + * Simple variable-capacity data structure (opaque type). + */ +struct _flib_vector; +typedef struct _flib_vector *flib_vector; + +/** + * Create a new vector. Needs to be destroyed again later with flib_vector_destroy. + * May return NULL if memory runs out. + */ +flib_vector flib_vector_create(); + +/** + * Free the memory of this vector and set it to NULL. + */ +void flib_vector_destroy(flib_vector *vec); + +/** + * Append the provided data to the end of the vector, enlarging it as required. + * Returns the ammount of data appended, which is either len (success) or 0 (out of memory). + * The vector remains unchanged if an out of memory situation occurs. + */ +int flib_vector_append(flib_vector vec, const void *data, size_t len); + +/** + * Return a buffer or constbuffer pointing to the current contents of the vector. + * These will become invalid if the vector size or capacity is changed. + */ +flib_buffer flib_vector_as_buffer(flib_vector vec); +flib_constbuffer flib_vector_as_constbuffer(flib_vector vec); + + +#endif diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/inihelper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/inihelper.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,168 @@ +#include "inihelper.h" +#include "logging.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include + +static bool keychar_needs_urlencoding(char c) { + return !isalnum(c); +} + +char *inihelper_urlencode(const char *inbuf) { + if(!inbuf) { + return NULL; + } + size_t insize = strlen(inbuf); + if(insize > SIZE_MAX/4) { + return NULL; + } + + char *outbuf = malloc(insize*3+1); + if(!outbuf) { + return NULL; + } + + size_t inpos = 0, outpos = 0; + while(inbuf[inpos]) { + if(!keychar_needs_urlencoding(inbuf[inpos])) { + outbuf[outpos++] = inbuf[inpos++]; + } else { + if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { + free(outbuf); + return NULL; + } + inpos++; + outpos += 3; + } + } + outbuf[outpos] = 0; + return outbuf; +} + +char *inihelper_urldecode(const char *inbuf) { + char *outbuf = malloc(strlen(inbuf)+1); + if(!outbuf) { + return NULL; + } + + size_t inpos = 0, outpos = 0; + while(inbuf[inpos]) { + if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { + char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; + outbuf[outpos++] = strtol(temp, NULL, 16); + inpos += 3; + } else { + outbuf[outpos++] = inbuf[inpos++]; + } + } + outbuf[outpos] = 0; + return outbuf; +} + +char *inihelper_createDictKey(const char *sectionName, const char *keyName) { + if(!sectionName || !keyName) { + return NULL; + } + return flib_asprintf("%s:%s", sectionName, keyName); +} + +char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { + if(!inifile || !sectionName || !keyName) { + *error = true; + return NULL; + } + char *extendedkey = inihelper_createDictKey(sectionName, keyName); + if(!extendedkey) { + *error = true; + return NULL; + } + char *result = iniparser_getstring(inifile, extendedkey, NULL); + free(extendedkey); + if(!result) { + flib_log_i("Missing ini setting: %s/%s", sectionName, keyName); + *error = true; + } + return result; +} + +char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { + return flib_strdupnull(inihelper_getstring(inifile, error, sectionName, keyName)); +} + +int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { + char *value = inihelper_getstring(inifile, error, sectionName, keyName); + if(!value) { + return 0; + } else { + errno = 0; + long val = strtol(value, NULL, 10); + if(errno!=0) { + *error = true; + return 0; + } + if(valINT_MAX) { + *error = true; + return 0; + } + return (int)val; + } +} + +bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) { + char *value = inihelper_getstring(inifile, error, sectionName, keyName); + if(!value) { + return false; + } else { + bool trueval = strchr("1tTyY", value[0]); + bool falseval = strchr("0fFnN", value[0]); + if(!trueval && !falseval) { + *error = true; + return false; + } else { + return trueval; + } + } +} + +int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value) { + int result = -1; + if(!dict || !sectionName || !keyName || !value) { + flib_log_e("inihelper_setstr called with bad parameters"); + } else { + char *extendedkey = inihelper_createDictKey(sectionName, keyName); + if(extendedkey) { + result = iniparser_set(dict, extendedkey, value); + free(extendedkey); + } + } + return result; +} + +int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value) { + int result = -1; + if(!dict || !sectionName || !keyName) { + flib_log_e("inihelper_setint called with bad parameters"); + } else { + char *strvalue = flib_asprintf("%i", value); + if(strvalue) { + result = inihelper_setstr(dict, sectionName, keyName, strvalue); + free(strvalue); + } + } + return result; +} + +int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value) { + int result = -1; + if(!dict || !sectionName || !keyName) { + flib_log_e("inihelper_setint called with bad parameters"); + } else { + result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false"); + } + return result; +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/inihelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/inihelper.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,54 @@ +/** + * Some helper functions for working with the iniparser functions - in particular, + * for interoperability with the ini format used by the QtSettings class. + */ + +#ifndef INIHELPER_H_ +#define INIHELPER_H_ + +#include "../iniparser/iniparser.h" + +#include + +/** + * Returned buffer must be free()d + */ +char *inihelper_urlencode(const char *inbuf); + +/** + * Returned buffer must be free()d + */ +char *inihelper_urldecode(const char *inbuf); + +/** + * Create a key in the format "sectionName:keyName" + * Returned buffer must be free()d + */ +char *inihelper_createDictKey(const char *sectionName, const char *keyName); + +/** + * Returns an internal buffer, don't modify or free + * Sets error to true if something goes wrong, leaves it unchanged otherwise. + */ +char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); + +/** + * Returned buffer must be free()d + * Sets error to true if something goes wrong, leaves it unchanged otherwise. + */ +char *inihelper_getstringdup(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); + +/** + * Sets error to true if something goes wrong, leaves it unchanged otherwise. + */ +int inihelper_getint(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); + +/** + * Sets error to true if something goes wrong, leaves it unchanged otherwise. + */ +bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName); + +int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value); +int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value); +int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value); +#endif /* INIHELPER_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/logging.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/logging.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,53 @@ +#include "logging.h" + +#include +#include +#include +#include + +char* flib_format_ip(uint32_t numip) { + static char ip[16]; + snprintf(ip, 16, "%u.%u.%u.%u", (unsigned)(numip>>24), (unsigned)((numip>>16)&0xff), (unsigned)((numip>>8)&0xff), (unsigned)(numip&0xff)); + return ip; +} + +static void log_time(FILE *file) { + time_t timer; + char buffer[25]; + struct tm* tm_info; + + time(&timer); + tm_info = localtime(&timer); + + strftime(buffer, 25, "%Y-%m-%d %H:%M:%S", tm_info); + fprintf(file, "%s", buffer); +} + +static void flib_vflog(FILE *file, const char *prefix, const char *fmt, va_list args) { + log_time(file); + fprintf(file, " [%s]", prefix); + vfprintf(file, fmt, args); + fprintf(file, "\n"); + fflush(file); +} + +void flib_log_e(const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + flib_vflog(stderr, "E", fmt, argp); + va_end(argp); +} + +void flib_log_w(const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + flib_vflog(stdout, "W", fmt, argp); + va_end(argp); +} + +void flib_log_i(const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + flib_vflog(stdout, "I", fmt, argp); + va_end(argp); +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/logging.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,16 @@ +/* + * + */ + +#ifndef LOGGING_H_ +#define LOGGING_H_ + +#include + +char* flib_format_ip(uint32_t numip); + +void flib_log_e(const char *fmt, ...); +void flib_log_w(const char *fmt, ...); +void flib_log_i(const char *fmt, ...); + +#endif /* LOGGING_H_ */ diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/util.c Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,49 @@ +#include "util.h" + +#include +#include +#include +#include +#include + +char *flib_asprintf(const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + char *result = flib_vasprintf(fmt, argp); + va_end(argp); + return result; +} + +char *flib_vasprintf(const char *fmt, va_list args) { + char *result = NULL; + int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, + if(requiredSize>=0) { + char *tmpbuf = malloc(requiredSize); // allocate it + if(tmpbuf) { + if(vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. + result = tmpbuf; + tmpbuf = NULL; + } + } + free(tmpbuf); + } + return result; +} + +char *flib_strdupnull(const char *str) { + if(!str) { + return NULL; + } + return flib_asprintf("%s", str); +} + +void *flib_bufdupnull(const void *buf, size_t size) { + if(!buf || size==0) { + return NULL; + } + void *result = malloc(size); + if(result) { + memcpy(result, buf, size); + } + return result; +} diff -r bf6cf4dd847a -r f84805e6df03 project_files/frontlib/util/util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/util.h Sat Jun 09 03:28:38 2012 +0200 @@ -0,0 +1,36 @@ +#ifndef FLIB_UTIL_H_ +#define FLIB_UTIL_H_ + +#include +#include + +/** + * Prints a format string to a newly allocated buffer of the required size. + * Parameters are like those for printf. Returns NULL on error. + * + * Returned buffer must be free()d + */ +char *flib_asprintf(const char *fmt, ...); + +/** + * Exactly as flib_asprintf, but accepts va_args. + */ +char *flib_vasprintf(const char *fmt, va_list args); + +/** + * Return a duplicate of the provided string, or NULL if an error + * occurs or if str is already NULL. + * + * Returned buffer must be free()d + */ +char *flib_strdupnull(const char *str); + +/** + * Return a duplicate of the provided buffer, or NULL if an error + * occurs or if buf is already NULL or if size is 0. + * + * Returned buffer must be free()d + */ +void *flib_bufdupnull(const void *buf, size_t size); + +#endif