# HG changeset patch # User Medo # Date 1339783045 -7200 # Node ID 240620f46dd74dc05dac033b0a8e197e05a9aece # Parent 1c859f572d72c341a4c02aa21e15572cb5c9e6df Changed frontlib to use the existing ini file formats of the QtFrontend diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/hwconsts.h --- a/project_files/frontlib/hwconsts.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/hwconsts.h Fri Jun 15 19:57:25 2012 +0200 @@ -13,9 +13,5 @@ #define GAMEMOD_SHAREDAMMO_MASKBIT 16 #define WEAPONS_COUNT 55 -#define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111011" -#define AMMOLINE_DEFAULT_PROB "0405040541600655546554464776576666666155510101115411011" -#define AMMOLINE_DEFAULT_DELAY "0000000000000205500000040007004000000000220000000600000" -#define AMMOLINE_DEFAULT_CRATE "1311110312111111123114111111111111111211111101111111010" #endif diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/ipc/gameconn.c --- a/project_files/frontlib/ipc/gameconn.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.c Fri Jun 15 19:57:25 2012 +0200 @@ -63,43 +63,6 @@ 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 = flib_calloc(1, sizeof(flib_gameconn)); @@ -122,11 +85,11 @@ return result; } -flib_gameconn *flib_gameconn_create(const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) { +flib_gameconn *flib_gameconn_create(const char *playerName, 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) { + if(!flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) { result = tempConn; tempConn = NULL; } diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/ipc/gameconn.h --- a/project_files/frontlib/ipc/gameconn.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.h Fri Jun 15 19:57:25 2012 +0200 @@ -16,7 +16,7 @@ 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(const char *playerName, 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); @@ -75,4 +75,6 @@ */ void flib_gameconn_onNetMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context); +// TODO efinish + #endif diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/ipc/ipcprotocol.c --- a/project_files/frontlib/ipc/ipcprotocol.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.c Fri Jun 15 19:57:25 2012 +0200 @@ -6,6 +6,7 @@ #include #include #include +#include int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) { int result = -1; @@ -38,7 +39,7 @@ return result; } -int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview) { +int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) { int result = -1; flib_vector *tempvector = flib_vector_create(); if(!vec || !map) { @@ -96,12 +97,13 @@ } } -int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *scheme, flib_cfg_meta *meta) { +int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *scheme) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !scheme || !meta) { + if(!vec || !scheme) { flib_log_e("null parameter in flib_ipc_append_gamescheme"); } else if(tempvector) { + const flib_cfg_meta *meta = scheme->meta; bool error = false; uint32_t gamemods = 0; for(int i=0; imodCount; i++) { @@ -112,8 +114,8 @@ 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].maxMeansInfinity) { + value = value>=meta->settings[i].max ? 9999 : value; } if(meta->settings[i].times1000) { value *= 1000; @@ -133,19 +135,23 @@ 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) { +static int appendWeaponSet(flib_vector *vec, flib_weaponset *set) { + return flib_ipc_append_message(vec, "eammloadt %s", set->loadout) + || flib_ipc_append_message(vec, "eammprob %s", set->crateprob) + || flib_ipc_append_message(vec, "eammdelay %s", set->delay) + || flib_ipc_append_message(vec, "eammreinf %s", set->crateammo); +} + +int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !team || !team->weaponset) { + if(!vec || !team) { 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) { + + if(!perHogAmmo && !noAmmoStore) { + error |= appendWeaponSet(tempvector, team->hogs[0].weaponset); error |= flib_ipc_append_message(tempvector, "eammstore"); } @@ -166,6 +172,9 @@ } for(int i=0; ihogsInGame; i++) { + if(perHogAmmo && !noAmmoStore) { + error |= appendWeaponSet(tempvector, team->hogs[i].weaponset); + } 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); } @@ -181,3 +190,80 @@ flib_vector_destroy(tempvector); return result; } + +static bool getGameMod(const flib_cfg *conf, int maskbit) { + for(int i=0; imeta->modCount; i++) { + if(conf->meta->mods[i].bitmaskIndex == maskbit) { + return conf->mods[i]; + } + } + flib_log_e("Unable to find game mod with mask bit %i", maskbit); + return false; +} + +int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) { + int result = -1; + flib_vector *tempvector = flib_vector_create(); + if(!vec || !setup) { + flib_log_e("null parameter in flib_ipc_append_fullconfig"); + } else if(tempvector) { + bool error = false; + bool perHogAmmo = false; + bool sharedAmmo = false; + + error |= flib_ipc_append_message(vec, netgame ? "TN" : "TL"); + error |= flib_ipc_append_seed(vec, setup->seed); + if(setup->map) { + error |= flib_ipc_append_mapconf(tempvector, setup->map, false); + } + if(setup->script) { + error |= flib_ipc_append_message(tempvector, "escript %s", setup->script); + } + if(setup->gamescheme) { + error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme); + sharedAmmo = getGameMod(setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT); + // Shared ammo has priority over per-hog ammo + perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT); + } + if(setup->teams && setup->teamcount>0) { + uint32_t *clanColors = flib_calloc(setup->teamcount, sizeof(uint32_t)); + if(!clanColors) { + error = true; + } else { + int clanCount = 0; + for(int i=0; iteamcount; i++) { + flib_team *team = setup->teams[i]; + bool newClan = false; + + // Find the clan index of this team (clans are identified by color). + // The upper 8 bits (alpha) are ignored in the engine as well. + uint32_t color = team->color&UINT32_C(0x00ffffff); + int clan = 0; + while(clanteams[i], perHogAmmo, noAmmoStore); + } + } + free(clanColors); + } + error |= flib_ipc_append_message(tempvector, "!"); + + 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; + } + } + } + return result; +} diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/ipc/ipcprotocol.h --- a/project_files/frontlib/ipc/ipcprotocol.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.h Fri Jun 15 19:57:25 2012 +0200 @@ -5,6 +5,7 @@ #include "../model/map.h" #include "../model/team.h" #include "../model/cfg.h" +#include "../model/gamesetup.h" #include @@ -27,7 +28,7 @@ * Returns nonzero if something goes wrong. In that case the buffer * contents are unaffected. */ -int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview); +int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview); /** * Append a seed message to the buffer. @@ -43,8 +44,10 @@ * 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_gamescheme(flib_vector *vec, const flib_cfg *cfg); -int flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo); +int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore); + +int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame); #endif /* IPCPROTOCOL_H_ */ diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/cfg.c --- a/project_files/frontlib/model/cfg.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/cfg.c Fri Jun 15 19:57:25 2012 +0200 @@ -3,96 +3,25 @@ #include "../util/inihelper.h" #include "../util/logging.h" #include "../util/util.h" +#include "../util/refcounter.h" #include #include - -static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *settingfile, flib_ini *modfile) { - flib_cfg_meta_destroy(result); - flib_ini_destroy(settingfile); - flib_ini_destroy(modfile); - return NULL; -} - -flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) { - if(!settingpath || !modpath) { - flib_log_e("null parameter in flib_cfg_meta_from_ini"); - return NULL; - } - flib_cfg_meta *result = flib_calloc(1, sizeof(flib_cfg_meta)); - flib_ini *settingfile = flib_ini_load(settingpath); - flib_ini *modfile = flib_ini_load(modpath); - - if(!result || !settingfile || !modfile) { - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } - - result->settingCount = flib_ini_get_sectioncount(settingfile); - result->modCount = flib_ini_get_sectioncount(modfile); - result->settings = flib_calloc(result->settingCount, sizeof(flib_cfg_setting_meta)); - result->mods = flib_calloc(result->modCount, sizeof(flib_cfg_mod_meta)); - - if(!result->settings || !result->mods) { - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } - - for(int i=0; isettingCount; i++) { - result->settings[i].iniName = flib_ini_get_sectionname(settingfile, i); - if(!result->settings[i].iniName) { - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } +#include +#include - bool error = false; - error |= flib_ini_enter_section(settingfile, result->settings[i].iniName); - error |= flib_ini_get_str(settingfile, &result->settings[i].title, "title"); - error |= flib_ini_get_str(settingfile, &result->settings[i].engineCommand, "command"); - error |= flib_ini_get_str(settingfile, &result->settings[i].image, "image"); - error |= flib_ini_get_bool(settingfile, &result->settings[i].checkOverMax, "checkOverMax"); - error |= flib_ini_get_bool(settingfile, &result->settings[i].times1000, "times1000"); - error |= flib_ini_get_int(settingfile, &result->settings[i].min, "min"); - error |= flib_ini_get_int(settingfile, &result->settings[i].max, "max"); - error |= flib_ini_get_int(settingfile, &result->settings[i].def, "default"); - - if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, result->settings[i].iniName); - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } - } - - for(int i=0; imodCount; i++) { - result->mods[i].iniName = flib_ini_get_sectionname(modfile, i); - if(!result->mods[i].iniName) { - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } - - bool error = false; - error |= flib_ini_enter_section(modfile, result->mods[i].iniName); - error |= flib_ini_get_int(modfile, &result->mods[i].bitmaskIndex, "bitmaskIndex"); - if(error) { - flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, result->mods[i].iniName); - return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); - } - } - - flib_ini_destroy(settingfile); - flib_ini_destroy(modfile); - return result; -} - -void flib_cfg_meta_destroy(flib_cfg_meta *cfg) { +static void flib_cfg_meta_destroy(flib_cfg_meta *cfg) { if(cfg) { if(cfg->settings) { for(int i=0; isettingCount; i++) { - free(cfg->settings[i].iniName); - free(cfg->settings[i].title); + free(cfg->settings[i].name); free(cfg->settings[i].engineCommand); - free(cfg->settings[i].image); } free(cfg->settings); } if(cfg->mods) { for(int i=0; imodCount; i++) { - free(cfg->mods[i].iniName); + free(cfg->mods[i].name); } free(cfg->mods); } @@ -100,15 +29,132 @@ } } -flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName) { - flib_cfg *result = flib_calloc(1, sizeof(flib_cfg)); +static void flib_cfg_destroy(flib_cfg* cfg) { + if(cfg) { + flib_cfg_meta_release(cfg->meta); + free(cfg->mods); + free(cfg->settings); + free(cfg->schemeName); + free(cfg); + } +} + +static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *ini) { + flib_cfg_meta_destroy(result); + flib_ini_destroy(ini); + return NULL; +} + +static int readMetaSettingSections(flib_ini *ini, flib_cfg_meta *result, int limit) { + while(result->settingCountsettingCount) <= 0) { + return -1; + } + if(!flib_ini_enter_section(ini, sectionName)) { + flib_cfg_setting_meta *metasetting = &result->settings[result->settingCount]; + result->settingCount++; + + bool error = false; + error |= flib_ini_get_str(ini, &metasetting->name, "name"); + error |= flib_ini_get_str_opt(ini, &metasetting->engineCommand, "command", NULL); + error |= flib_ini_get_bool(ini, &metasetting->times1000, "times1000"); + error |= flib_ini_get_bool(ini, &metasetting->maxMeansInfinity, "maxmeansinfinity"); + error |= flib_ini_get_int(ini, &metasetting->min, "min"); + error |= flib_ini_get_int(ini, &metasetting->max, "max"); + error |= flib_ini_get_int(ini, &metasetting->def, "default"); + if(error) { + flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName); + return -1; + } + } else { + return 0; + } + } + return 0; +} + +static int readMetaModSections(flib_ini *ini, flib_cfg_meta *result, int limit) { + while(result->modCountmodCount) <= 0) { + return -1; + } + if(!flib_ini_enter_section(ini, sectionName)) { + flib_cfg_mod_meta *metamod = &result->mods[result->modCount]; + result->modCount++; + + bool error = false; + error |= flib_ini_get_str(ini, &metamod->name, "name"); + error |= flib_ini_get_int(ini, &metamod->bitmaskIndex, "bitmaskIndex"); + if(error) { + flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName); + return -1; + } + } else { + return 0; + } + } + return 0; +} + +flib_cfg_meta *flib_cfg_meta_from_ini(const char *filename) { + if(!filename) { + flib_log_e("null parameter in flib_cfg_meta_from_ini"); + return NULL; + } + flib_cfg_meta *result = flib_cfg_meta_retain(flib_calloc(1, sizeof(flib_cfg_meta))); + flib_ini *ini = flib_ini_load(filename); + + if(!result || !ini) { + return flib_cfg_meta_from_ini_handleError(result, ini); + } + + // We're overallocating here for simplicity + int sectionCount = flib_ini_get_sectioncount(ini); + result->settingCount = 0; + result->modCount = 0; + result->settings = flib_calloc(sectionCount, sizeof(flib_cfg_setting_meta)); + result->mods = flib_calloc(sectionCount, sizeof(flib_cfg_mod_meta)); + + if(!result->settings || !result->mods) { + return flib_cfg_meta_from_ini_handleError(result, ini); + } + + if(readMetaSettingSections(ini, result, sectionCount) || readMetaModSections(ini, result, sectionCount)) { + return flib_cfg_meta_from_ini_handleError(result, ini); + } + + if(result->settingCount+result->modCount != sectionCount) { + flib_log_e("Unknown or non-contiguous sections headers in metaconfig."); + return flib_cfg_meta_from_ini_handleError(result, ini); + } + + flib_ini_destroy(ini); + return result; +} + +flib_cfg_meta *flib_cfg_meta_retain(flib_cfg_meta *metainfo) { + if(metainfo) { + flib_retain(&metainfo->_referenceCount, "flib_cfg_meta"); + } + return metainfo; +} + +void flib_cfg_meta_release(flib_cfg_meta *cfg) { + if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg_meta")) { + flib_cfg_meta_destroy(cfg); + } +} + +flib_cfg *flib_cfg_create(flib_cfg_meta *meta, const char *schemeName) { + flib_cfg *result = flib_cfg_retain(flib_calloc(1, sizeof(flib_cfg))); if(!meta || !result || !schemeName) { flib_log_e("null parameter in flib_cfg_create"); return NULL; } - result->modCount = meta->modCount; - result->settingCount = meta->settingCount; + result->meta = flib_cfg_meta_retain(meta); result->schemeName = flib_strdupnull(schemeName); result->mods = flib_calloc(meta->modCount, sizeof(*result->mods)); result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings)); @@ -124,103 +170,27 @@ return result; } -flib_cfg *flib_cfg_from_ini_handleError(flib_cfg *result, flib_ini *settingfile) { - flib_ini_destroy(settingfile); - flib_cfg_destroy(result); - return NULL; -} - -flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename) { - if(!meta || !filename) { - flib_log_e("null parameter in flib_cfg_from_ini"); - return NULL; - } - flib_ini *settingfile = flib_ini_load(filename); - if(!settingfile) { - return NULL; - } - - char *schemename = NULL; - if(flib_ini_enter_section(settingfile, "Scheme")) { - flib_log_e("Missing section \"Scheme\" in config file %s.", filename); - return flib_cfg_from_ini_handleError(NULL, settingfile); - } - if(flib_ini_get_str(settingfile, &schemename, "name")) { - flib_log_e("Missing scheme name in config file %s.", filename); - return flib_cfg_from_ini_handleError(NULL, settingfile); - } - - flib_cfg *result = flib_cfg_create(meta, schemename); - - if(flib_ini_enter_section(settingfile, "BasicSettings")) { - flib_log_w("Missing section \"BasicSettings\" in config file %s, using defaults.", filename); - } else { - for(int i=0; isettingCount; i++) { - if(flib_ini_get_int_opt(settingfile, &result->settings[i], meta->settings[i].iniName, meta->settings[i].def)) { - flib_log_e("Error reading BasicSetting %s in config file %s.", meta->settings[i].iniName, filename); - return flib_cfg_from_ini_handleError(result, settingfile); - } +flib_cfg *flib_cfg_copy(flib_cfg *cfg) { + flib_cfg *result = NULL; + if(cfg) { + result = flib_cfg_create(cfg->meta, cfg->schemeName); + if(result) { + memcpy(result->mods, cfg->mods, cfg->meta->modCount * sizeof(*cfg->mods)); + memcpy(result->settings, cfg->settings, cfg->meta->settingCount * sizeof(*cfg->settings)); } } - - if(flib_ini_enter_section(settingfile, "GameMods")) { - flib_log_w("Missing section \"GameMods\" in config file %s, using defaults.", filename); - } else { - for(int i=0; imodCount; i++) { - if(flib_ini_get_bool_opt(settingfile, &result->mods[i], meta->mods[i].iniName, false)) { - flib_log_e("Error reading GameMod %s in config file %s.", meta->mods[i].iniName, filename); - return flib_cfg_from_ini_handleError(result, settingfile); - } - } - } - flib_ini_destroy(settingfile); - return result; -} - -int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config) { - int result = -1; - if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) { - flib_log_e("Invalid parameter in flib_cfg_to_ini"); - } else { - flib_ini *ini = flib_ini_create(filename); - if(ini) { - bool error = false; - - // Add the values - error |= flib_ini_create_section(ini, "Scheme"); - if(!error) { - error |= flib_ini_set_str(ini, "name", config->schemeName); - } - - - error |= flib_ini_create_section(ini, "BasicSettings"); - if(!error) { - for(int i=0; isettingCount; i++) { - error |= flib_ini_set_int(ini, meta->settings[i].iniName, config->settings[i]); - } - } - - error |= flib_ini_create_section(ini, "GameMods"); - if(!error) { - for(int i=0; imodCount; i++) { - error |= flib_ini_set_bool(ini, meta->mods[i].iniName, config->mods[i]); - } - } - - if(!error) { - result = flib_ini_save(ini, filename); - } - } - flib_ini_destroy(ini); - } return result; } -void flib_cfg_destroy(flib_cfg* cfg) { +flib_cfg *flib_cfg_retain(flib_cfg *cfg) { if(cfg) { - free(cfg->mods); - free(cfg->settings); - free(cfg->schemeName); - free(cfg); + flib_retain(&cfg->_referenceCount, "flib_cfg"); + } + return cfg; +} + +void flib_cfg_release(flib_cfg *cfg) { + if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg")) { + flib_cfg_destroy(cfg); } } diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/cfg.h --- a/project_files/frontlib/model/cfg.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/cfg.h Fri Jun 15 19:57:25 2012 +0200 @@ -1,9 +1,5 @@ /** * Data structures for game scheme information. - * - * Important conventions: - * - All data structures own what they point to. - * - Strings are never null pointers. */ #ifndef CFG_H_ @@ -11,66 +7,79 @@ #include +// TODO: cfg/config -> scheme + typedef struct { - char *iniName; - char *title; + char *name; char *engineCommand; - char *image; - int netplayIndex; - bool checkOverMax; + bool maxMeansInfinity; bool times1000; - int def; int min; int max; + int def; } flib_cfg_setting_meta; typedef struct { - char *iniName; + char *name; int bitmaskIndex; } flib_cfg_mod_meta; typedef struct { - int settingCount; - int modCount; + int _referenceCount; + int settingCount; + int modCount; flib_cfg_setting_meta *settings; flib_cfg_mod_meta *mods; } flib_cfg_meta; typedef struct { - int settingCount; - int modCount; + int _referenceCount; + flib_cfg_meta *meta; + char *schemeName; int *settings; bool *mods; } flib_cfg; /** - * Read the meta-configuration from the relevant .ini files (e.g. which settings exist, + * Read the meta-configuration from a .ini file (e.g. which settings exist, * what are their defaults etc.) * - * Returns the meta-configuration or NULL. Destroy the meta-configuration with - * flib_cfg_meta_destroy. + * Returns the meta-configuration or NULL. */ -flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath); -void flib_cfg_meta_destroy(flib_cfg_meta *metainfo); +flib_cfg_meta *flib_cfg_meta_from_ini(const char *filename); /** - * Create a new configuration with default settings. + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. + */ +flib_cfg_meta *flib_cfg_meta_retain(flib_cfg_meta *metainfo); + +/** + * Decrease the reference count of the object and free it if this was the last reference. + */ +void flib_cfg_meta_release(flib_cfg_meta *metainfo); + +/** + * Create a new configuration with everything set to default or false * Returns NULL on error. */ -flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName); +flib_cfg *flib_cfg_create(flib_cfg_meta *meta, const char *schemeName); + +/** + * Create a copy of the scheme. Returns NULL on error or if NULL was passed. + */ +flib_cfg *flib_cfg_copy(flib_cfg *cfg); /** - * Load a configuration from the ini file. - * Returns NULL on error. + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. */ -flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename); +flib_cfg *flib_cfg_retain(flib_cfg *cfg); /** - * Store the configuration to an ini file. - * Returns NULL on error. + * Decrease the reference count of the object and free it if this was the last reference. */ -int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config); -void flib_cfg_destroy(flib_cfg* cfg); +void flib_cfg_release(flib_cfg* cfg); #endif /* CFG_H_ */ diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/map.c --- a/project_files/frontlib/model/map.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/map.c Fri Jun 15 19:57:25 2012 +0200 @@ -3,9 +3,19 @@ #include "../util/inihelper.h" #include "../util/util.h" #include "../util/logging.h" +#include "../util/refcounter.h" #include +static void flib_map_destroy(flib_map *map) { + if(map) { + free(map->drawData); + free(map->name); + free(map->theme); + free(map); + } +} + flib_map *flib_map_create_regular(const char *theme, int templateFilter) { flib_map *result = NULL; if(!theme) { @@ -13,6 +23,7 @@ } else { flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { + newmap->_referenceCount = 1; newmap->mapgen = MAPGEN_REGULAR; newmap->templateFilter = templateFilter; newmap->theme = flib_strdupnull(theme); @@ -33,6 +44,7 @@ } else { flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { + newmap->_referenceCount = 1; newmap->mapgen = MAPGEN_MAZE; newmap->mazeSize = mazeSize; newmap->theme = flib_strdupnull(theme); @@ -53,6 +65,7 @@ } else { flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { + newmap->_referenceCount = 1; newmap->mapgen = MAPGEN_NAMED; newmap->name = flib_strdupnull(name); if(newmap->name) { @@ -72,6 +85,7 @@ } else { flib_map *newmap = flib_calloc(1, sizeof(flib_map)); if(newmap) { + newmap->_referenceCount = 1; newmap->mapgen = MAPGEN_DRAWN; newmap->drawData = flib_bufdupnull(drawData, drawDataSize); newmap->drawDataSize = drawDataSize; @@ -85,11 +99,15 @@ return result; } -void flib_map_destroy(flib_map *map) { +flib_map *flib_map_retain(flib_map *map) { if(map) { - free(map->drawData); - free(map->name); - free(map->theme); - free(map); + flib_retain(&map->_referenceCount, "flib_map"); + } + return map; +} + +void flib_map_release(flib_map *map) { + if(map && flib_release(&map->_referenceCount, "flib_map")) { + flib_map_destroy(map); } } diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/map.h --- a/project_files/frontlib/model/map.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/map.h Fri Jun 15 19:57:25 2012 +0200 @@ -30,6 +30,7 @@ #define MAZE_SIZE_LARGE_ISLANDS 5 typedef struct { + int _referenceCount; int mapgen; // Always one of the MAPGEN_ constants char *theme; // Used for all except MAPGEN_NAMED char *name; // Used for MAPGEN_NAMED @@ -79,9 +80,15 @@ flib_map *flib_map_create_drawn(const char *theme, const uint8_t *drawData, int drawDataSize); /** - * Free the memory taken up by the map. Passing NULL is allowed and does nothing. + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. */ -void flib_map_destroy(flib_map *map); +flib_map *flib_map_retain(flib_map *map); + +/** + * Decrease the reference count of the object and free it if this was the last reference. + */ +void flib_map_release(flib_map *map); #endif diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/schemelist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/schemelist.c Fri Jun 15 19:57:25 2012 +0200 @@ -0,0 +1,229 @@ +#include "schemelist.h" + +#include "../util/inihelper.h" +#include "../util/logging.h" +#include "../util/util.h" +#include "../util/refcounter.h" + +#include +#include +#include +#include + +static void flib_schemelist_destroy(flib_schemelist *list) { + if(list) { + for(int i=0; ischemeCount; i++) { + flib_cfg_release(list->schemes[i]); + } + free(list); + } +} + +static char *makePrefixedName(int schemeIndex, const char *settingName) { + return flib_asprintf("%i\\%s", schemeIndex, settingName); +} + +static int readSettingsFromIni(flib_ini *ini, flib_cfg *scheme, int index) { + flib_cfg_meta *meta = scheme->meta; + bool error = false; + for(int i=0; isettingCount && !error; i++) { + char *key = makePrefixedName(index, meta->settings[i].name); + if(!key) { + error = true; + } else if(flib_ini_get_int_opt(ini, &scheme->settings[i], key, meta->settings[i].def)) { + flib_log_e("Error reading setting %s in schemes file.", key); + error = true; + } + free(key); + } + return error; +} + +static int readModsFromIni(flib_ini *ini, flib_cfg *scheme, int index) { + flib_cfg_meta *meta = scheme->meta; + bool error = false; + for(int i=0; imodCount && !error; i++) { + char *key = makePrefixedName(index, meta->mods[i].name); + if(!key) { + error = true; + } else if(flib_ini_get_bool_opt(ini, &scheme->mods[i], key, false)) { + flib_log_e("Error reading mod %s in schemes file.", key); + error = true; + } + free(key); + } + return error; +} + +static flib_cfg *readSchemeFromIni(flib_cfg_meta *meta, flib_ini *ini, int index) { + flib_cfg *result = NULL; + char *schemeNameKey = makePrefixedName(index+1, "name"); + if(schemeNameKey) { + char *schemeName = NULL; + if(!flib_ini_get_str_opt(ini, &schemeName, schemeNameKey, "Unnamed")) { + flib_cfg *scheme = flib_cfg_create(meta, schemeName); + if(scheme) { + if(!readSettingsFromIni(ini, scheme, index) && !readModsFromIni(ini, scheme, index)) { + result = flib_cfg_retain(scheme); + } + } + flib_cfg_release(scheme); + } + free(schemeName); + } + free(schemeNameKey); + return result; +} + +static flib_schemelist *fromIniHandleError(flib_schemelist *result, flib_ini *ini) { + flib_ini_destroy(ini); + flib_schemelist_destroy(result); + return NULL; +} + +flib_schemelist *flib_schemelist_from_ini(flib_cfg_meta *meta, const char *filename) { + flib_schemelist *list = NULL; + if(!meta || !filename) { + flib_log_e("null parameter in flib_schemelist_from_ini"); + return NULL; + } + flib_ini *ini = flib_ini_load(filename); + if(!ini || flib_ini_enter_section(ini, "schemes")) { + flib_log_e("Missing file or missing section \"schemes\" in file %s.", filename); + return fromIniHandleError(list, ini); + } + + list = flib_schemelist_create(); + if(!list) { + return fromIniHandleError(list, ini); + } + + int schemeCount = 0; + if(flib_ini_get_int(ini, &schemeCount, "size")) { + flib_log_e("Missing or malformed scheme count in config file %s.", filename); + return fromIniHandleError(list, ini); + } + + for(int i=0; imeta; + bool error = false; + + char *key = makePrefixedName(index+1, "name"); + error |= !key || flib_ini_set_str(ini, key, scheme->schemeName); + free(key); + + for(int i=0; imodCount && !error; i++) { + char *key = makePrefixedName(index+1, meta->mods[i].name); + error |= !key || flib_ini_set_bool(ini, key, scheme->mods[i]); + free(key); + } + + for(int i=0; isettingCount && !error; i++) { + char *key = makePrefixedName(index+1, meta->settings[i].name); + error |= !key || flib_ini_set_int(ini, key, scheme->settings[i]); + free(key); + } + return error; +} + +int flib_schemelist_to_ini(const char *filename, const flib_schemelist *schemes) { + int result = -1; + if(!filename || !schemes) { + flib_log_e("null parameter in flib_schemelist_to_ini"); + } else { + flib_ini *ini = flib_ini_create(NULL); + if(ini && !flib_ini_create_section(ini, "schemes")) { + bool error = false; + error |= flib_ini_set_int(ini, "size", schemes->schemeCount); + for(int i=0; ischemeCount && !error; i++) { + error |= writeSchemeToIni(schemes->schemes[i], ini, i); + } + + if(!error) { + result = flib_ini_save(ini, filename); + } + } + flib_ini_destroy(ini); + } + return result; +} + +flib_schemelist *flib_schemelist_create() { + return flib_schemelist_retain(flib_calloc(1, sizeof(flib_schemelist))); +} + +flib_schemelist *flib_schemelist_retain(flib_schemelist *list) { + if(list) { + flib_retain(&list->_referenceCount, "flib_schemelist"); + } + return list; +} + +void flib_schemelist_release(flib_schemelist *list) { + if(list && flib_release(&list->_referenceCount, "flib_schemelist")) { + flib_schemelist_destroy(list); + } +} + +flib_cfg *flib_schemelist_find(flib_schemelist *list, const char *name) { + if(list && name) { + for(int i=0; ischemeCount; i++) { + if(!strcmp(name, list->schemes[i]->schemeName)) { + return list->schemes[i]; + } + } + } + return NULL; +} + +int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos) { + int result = -1; + if(!list || !cfg || pos < 0 || pos > list->schemeCount) { + flib_log_e("Invalid parameter in flib_schemelist_insert"); + } else { + flib_cfg **newSchemes = flib_realloc(list->schemes, (list->schemeCount+1)*sizeof(*list->schemes)); + if(newSchemes) { + list->schemes = newSchemes; + memmove(list->schemes+pos+1, list->schemes+pos, (list->schemeCount-pos)*sizeof(*list->schemes)); + list->schemes[pos] = flib_cfg_retain(cfg); + list->schemeCount++; + result = 0; + } + } + return result; +} + +int flib_schemelist_delete(flib_schemelist *list, int pos) { + int result = -1; + if(!list || pos < 0 || pos >= list->schemeCount) { + flib_log_e("Invalid parameter in flib_schemelist_delete"); + } else { + flib_cfg_release(list->schemes[pos]); + memmove(list->schemes+pos, list->schemes+pos+1, (list->schemeCount-(pos+1))*sizeof(*list->schemes)); + list->schemes[list->schemeCount-1] = NULL; + list->schemeCount--; + + // If the realloc fails, just keep using the old buffer... + flib_cfg **newSchemes = flib_realloc(list->schemes, list->schemeCount*sizeof(*list->schemes)); + if(newSchemes || list->schemeCount==1) { + list->schemes = newSchemes; + } + result = 0; + } + return result; +} diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/schemelist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/schemelist.h Fri Jun 15 19:57:25 2012 +0200 @@ -0,0 +1,67 @@ +/** + * Functions for managing a list of schemes. + * This is in here because the scheme config file of the QtFrontend (which we are staying compatble with) contains + * all the schemes at once, so we need functions to work with a list like that. + */ + +#ifndef SCHEMELIST_H_ +#define SCHEMELIST_H_ + +#include "cfg.h" + +typedef struct { + int _referenceCount; + int schemeCount; + flib_cfg **schemes; +} flib_schemelist; + +/** + * Load a list of configurations from the ini file. + * Returns NULL on error. + */ +flib_schemelist *flib_schemelist_from_ini(flib_cfg_meta *meta, const char *filename); + +/** + * Store the list of configurations to an ini file. + * Returns NULL on error. + */ +int flib_schemelist_to_ini(const char *filename, const flib_schemelist *config); + +/** + * Create an empty scheme list. Returns NULL on error. + */ +flib_schemelist *flib_schemelist_create(); + +/** + * Insert a new scheme into the list at position pos, moving all higher schemes to make place. + * pos must be at least 0 (insert at the start) and at most list->schemeCount (insert at the end). + * The scheme is retained automatically. + * Returns 0 on success. + */ +int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos); + +/** + * Delete a cfg from the list at position pos, moving down all higher schemes. + * The scheme is released automatically. + * Returns 0 on success. + */ +int flib_schemelist_delete(flib_schemelist *list, int pos); + +/** + * Find the scheme with a specific name + */ +flib_cfg *flib_schemelist_find(flib_schemelist *list, const char *name); + +/** + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. + */ +flib_schemelist *flib_schemelist_retain(flib_schemelist *list); + +/** + * Decrease the reference count of the object and free it if this was the last reference. + */ +void flib_schemelist_release(flib_schemelist *list); + + +#endif /* SCHEMELIST_H_ */ diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/team.c --- a/project_files/frontlib/model/team.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/team.c Fri Jun 15 19:57:25 2012 +0200 @@ -194,6 +194,7 @@ for(int i=0; ihogs[i].name); free(team->hogs[i].hat); + flib_weaponset_release(team->hogs[i].weaponset); } free(team->name); free(team->grave); @@ -208,7 +209,15 @@ } free(team->bindings); free(team->hash); - flib_weaponset_destroy(team->weaponset); free(team); } } + +void flib_team_set_weaponset(flib_team *team, flib_weaponset *set) { + if(team) { + for(int i=0; ihogs[i].weaponset); + team->hogs[i].weaponset = flib_weaponset_retain(set); + } + } +} diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/team.h --- a/project_files/frontlib/model/team.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/team.h Fri Jun 15 19:57:25 2012 +0200 @@ -34,6 +34,7 @@ // Transient setting used in game setup int initialHealth; + flib_weaponset *weaponset; } flib_hog; typedef struct { @@ -57,9 +58,7 @@ uint32_t color; int hogsInGame; bool remoteDriven; - char *hash; // TODO calculate - - flib_weaponset *weaponset; + char *hash; // TODO calculate at the appropriate time... i.e. before trying to send the config to the engine } flib_team; /** @@ -85,6 +84,12 @@ * first hog is used for the entire team when writing. */ int flib_team_to_ini(const char *filename, const flib_team *team); + +/** + * Set the same weaponset for every hog in the team + */ +void flib_team_set_weaponset(flib_team *team, flib_weaponset *set); + void flib_team_destroy(flib_team *team); #endif /* TEAM_H_ */ diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/weapon.c --- a/project_files/frontlib/model/weapon.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/weapon.c Fri Jun 15 19:57:25 2012 +0200 @@ -3,118 +3,177 @@ #include "../util/inihelper.h" #include "../util/logging.h" #include "../util/util.h" +#include "../util/refcounter.h" #include #include - -int set_field(char field[WEAPONS_COUNT+1], const char *line, bool no9) { - // Validate the new string - for(int i=0; i '9' || (no9 && line[i] == '9')) { - flib_log_e("Invalid character in weapon config string \"%.*s\", position %i", WEAPONS_COUNT, line, i); - return -1; - } - } - - bool lineEnded = false; - for(int i=0; i -static flib_weaponset *flib_weaponset_create_str(const char *name, const char *loadoutStr, const char *crateProbStr, const char *crateAmmoStr, const char *delayStr) { - flib_weaponset *result = NULL; - if(!name || !loadoutStr || !crateProbStr || !crateAmmoStr || !delayStr) { - flib_log_e("null parameter in flib_weaponset_create_str"); - } else { - flib_weaponset *newSet = flib_calloc(1, sizeof(flib_weaponset)); - char *nameCopy = flib_strdupnull(name); - if(newSet && nameCopy) { - newSet->name = nameCopy; - nameCopy = NULL; - bool error = false; - error |= set_field(newSet->loadout, loadoutStr, false); - error |= set_field(newSet->crateprob, crateProbStr, false); - error |= set_field(newSet->crateammo, crateAmmoStr, false); - error |= set_field(newSet->delay, delayStr, false); - if(!error) { - result = newSet; - newSet = NULL; - } - } - free(nameCopy); - flib_weaponset_destroy(newSet); - } - return result; -} - -void flib_weaponset_destroy(flib_weaponset *cfg) { +static void flib_weaponset_destroy(flib_weaponset *cfg) { if(cfg) { free(cfg->name); free(cfg); } } +static void setField(char field[WEAPONS_COUNT+1], const char *line, int lineLen, bool no9) { + if(lineLen>WEAPONS_COUNT) { + lineLen = WEAPONS_COUNT; + } + + char min = '0'; + char max = no9 ? '8' : '9'; + for(int i=0; i= min && line[i] <= max) { + field[i] = line[i]; + } else { + flib_log_w("Invalid character in weapon config string \"%.*s\", position %i", lineLen, line, i); + field[i] = '0'; + } + } + for(int i=lineLen; iname = flib_strdupnull(name); + if(newSet->name) { + setField(newSet->loadout, "", 0, false); + setField(newSet->crateprob, "", 0, false); + setField(newSet->crateammo, "", 0, false); + setField(newSet->delay, "", 0, false); + result = flib_weaponset_retain(newSet); + } + } + flib_weaponset_release(newSet); + } + return result; +} + +flib_weaponset *flib_weaponset_retain(flib_weaponset *weaponset) { + if(weaponset) { + flib_retain(&weaponset->_referenceCount, "flib_weaponset"); + } + return weaponset; } -flib_weaponset *flib_weaponset_from_ini(const char *filename) { - flib_weaponset *result = NULL; +void flib_weaponset_release(flib_weaponset *weaponset) { + if(weaponset && flib_release(&weaponset->_referenceCount, "flib_weaponset")) { + flib_weaponset_destroy(weaponset); + } +} + +static void flib_weaponsetlist_destroy(flib_weaponsetlist *list) { + if(list) { + for(int i=0; iweaponsetCount; i++) { + flib_weaponset_release(list->weaponsets[i]); + } + free(list); + } +} + +static int fillWeaponsetFromIni(flib_weaponsetlist *list, flib_ini *ini, int index) { + int result = -1; + char *keyname = flib_ini_get_keyname(ini, index); + char *decodedKeyname = flib_urldecode(keyname); + + if(decodedKeyname) { + flib_weaponset *set = flib_weaponset_create(decodedKeyname); + if(set) { + char *value = NULL; + if(!flib_ini_get_str(ini, &value, keyname)) { + int fieldlen = strlen(value)/4; + setField(set->loadout, value, fieldlen, false); + setField(set->crateprob, value+1*fieldlen, fieldlen, true); + setField(set->delay, value+2*fieldlen, fieldlen, true); + setField(set->crateammo, value+3*fieldlen, fieldlen, true); + result = flib_weaponsetlist_insert(list, set, list->weaponsetCount); + } + free(value); + } + flib_weaponset_release(set); + } + + free(keyname); + free(decodedKeyname); + return result; +} + +static int fillWeaponsetsFromIni(flib_weaponsetlist *list, flib_ini *ini) { + bool error = false; + int weaponsets = flib_ini_get_keycount(ini); + + for(int i=0; i='0' && c<='9') || (c>='a' && c <='z')); +} + + +static int writeWeaponsetToIni(flib_ini *ini, flib_weaponset *set) { int result = -1; - if(!filename || !set) { - flib_log_e("null parameter in flib_weaponset_to_ini"); + char weaponstring[WEAPONS_COUNT*4+1]; + strcpy(weaponstring, set->loadout); + strcat(weaponstring, set->crateprob); + strcat(weaponstring, set->delay); + strcat(weaponstring, set->crateammo); + + char *escapedname = flib_urlencode_pred(set->name, needsEscape); + if(escapedname) { + result = flib_ini_set_str(ini, escapedname, weaponstring); + } + free(escapedname); + return result; +} + +int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *list) { + int result = -1; + if(!filename || !list) { + flib_log_e("null parameter in flib_weaponsetlist_to_ini"); } else { - flib_ini *ini = flib_ini_create(filename); - if(!flib_ini_create_section(ini, "weaponset")) { + flib_ini *ini = flib_ini_create(NULL); + if(ini && !flib_ini_create_section(ini, "General")) { bool error = false; - error |= flib_ini_set_str(ini, "name", set->name); - error |= flib_ini_set_str(ini, "loadout", set->loadout); - error |= flib_ini_set_str(ini, "crateprob", set->crateprob); - error |= flib_ini_set_str(ini, "crateammo", set->crateammo); - error |= flib_ini_set_str(ini, "delay", set->delay); + for(int i=0; iweaponsetCount && !error; i++) { + error |= writeWeaponsetToIni(ini, list->weaponsets[i]); + } + if(!error) { result = flib_ini_save(ini, filename); } @@ -123,3 +182,57 @@ } return result; } + +flib_weaponsetlist *flib_weaponsetlist_create() { + return flib_weaponsetlist_retain(flib_calloc(1, sizeof(flib_weaponsetlist))); +} + +int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos) { + int result = -1; + if(!list || !weaponset || pos < 0 || pos > list->weaponsetCount) { + flib_log_e("Invalid parameter in flib_weaponsetlist_insert"); + } else { + flib_weaponset **newSets = flib_realloc(list->weaponsets, (list->weaponsetCount+1)*sizeof(*list->weaponsets)); + if(newSets) { + list->weaponsets = newSets; + memmove(list->weaponsets+pos+1, list->weaponsets+pos, (list->weaponsetCount-pos)*sizeof(*list->weaponsets)); + list->weaponsets[pos] = flib_weaponset_retain(weaponset); + list->weaponsetCount++; + result = 0; + } + } + return result; +} + +int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos) { + int result = -1; + if(!list || pos < 0 || pos >= list->weaponsetCount) { + flib_log_e("Invalid parameter in flib_weaponsetlist_delete"); + } else { + flib_weaponset_release(list->weaponsets[pos]); + memmove(list->weaponsets+pos, list->weaponsets+pos+1, (list->weaponsetCount-(pos+1))*sizeof(*list->weaponsets)); + list->weaponsets[list->weaponsetCount-1] = NULL; + list->weaponsetCount--; + + // If the realloc fails, just keep using the old buffer... + flib_weaponset **newSets = flib_realloc(list->weaponsets, list->weaponsetCount*sizeof(*list->weaponsets)); + if(newSets || list->weaponsetCount==1) { + list->weaponsets = newSets; + } + result = 0; + } + return result; +} + +flib_weaponsetlist *flib_weaponsetlist_retain(flib_weaponsetlist *list) { + if(list) { + flib_retain(&list->_referenceCount, "flib_weaponsetlist"); + } + return list; +} + +void flib_weaponsetlist_release(flib_weaponsetlist *list) { + if(list && flib_release(&list->_referenceCount, "flib_weaponsetlist")) { + flib_weaponsetlist_destroy(list); + } +} diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/model/weapon.h --- a/project_files/frontlib/model/weapon.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/model/weapon.h Fri Jun 15 19:57:25 2012 +0200 @@ -10,6 +10,7 @@ * For the other setting, 9 is invalid. */ typedef struct { + int _referenceCount; char loadout[WEAPONS_COUNT+1]; char crateprob[WEAPONS_COUNT+1]; char crateammo[WEAPONS_COUNT+1]; @@ -17,6 +18,12 @@ char *name; } flib_weaponset; +typedef struct { + int _referenceCount; + int weaponsetCount; + flib_weaponset **weaponsets; +} flib_weaponsetlist; + /** * Returns a new weapon set, or NULL on error. * name must not be NULL. @@ -27,15 +34,57 @@ flib_weaponset *flib_weaponset_create(const char *name); /** - * Loads a weapon set, returns NULL on error. + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. + */ +flib_weaponset *flib_weaponset_retain(flib_weaponset *weaponset); + +/** + * Decrease the reference count of the object and free it if this was the last reference. */ -flib_weaponset *flib_weaponset_from_ini(const char *filename); +void flib_weaponset_release(flib_weaponset *weaponset); + +/** + * Load a list of weaponsets from the ini file. + * Returns NULL on error. + */ +flib_weaponsetlist *flib_weaponsetlist_from_ini(const char *filename); + +/** + * Store the list of weaponsets to an ini file. + * Returns NULL on error. + */ +int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *weaponsets); /** - * Write the weapon set to an ini file. Attempts to - * retain extra ini settings that were already present. + * Create an empty weaponset list. Returns NULL on error. + */ +flib_weaponsetlist *flib_weaponsetlist_create(); + +/** + * Insert a new weaponset into the list at position pos, moving all higher weaponsets to make place. + * pos must be at least 0 (insert at the start) and at most list->weaponsetCount (insert at the end). + * The weaponset is retained automatically. + * Returns 0 on success. */ -int flib_weaponset_to_ini(const char *filename, const flib_weaponset *set); -void flib_weaponset_destroy(flib_weaponset *set); +int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos); + +/** + * Delete a weaponset from the list at position pos, moving down all higher weaponsets. + * The weaponset is released automatically. + * Returns 0 on success. + */ +int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos); + +/** + * Increase the reference count of the object. Call this if you store a pointer to it somewhere. + * Returns the parameter. + */ +flib_weaponsetlist *flib_weaponsetlist_retain(flib_weaponsetlist *list); + +/** + * Decrease the reference count of the object and free it if this was the last reference. + */ +void flib_weaponsetlist_release(flib_weaponsetlist *list); #endif diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/resources/metasettings.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/resources/metasettings.ini Fri Jun 15 19:57:25 2012 +0200 @@ -0,0 +1,234 @@ +[mod0] +name=fortsmode +bitmaskindex=12 + +[mod1] +name=divteams +bitmaskindex=4 + +[mod2] +name=solidland +bitmaskindex=2 + +[mod3] +name=border +bitmaskindex=3 + +[mod4] +name=lowgrav +bitmaskindex=5 + +[mod5] +name=laser +bitmaskindex=6 + +[mod6] +name=invulnerability +bitmaskindex=7 + +[mod7] +name=resethealth +bitmaskindex=8 + +[mod8] +name=vampiric +bitmaskindex=9 + +[mod9] +name=karma +bitmaskindex=10 + +[mod10] +name=artillery +bitmaskindex=11 + +[mod11] +name=randomorder +bitmaskindex=13 + +[mod12] +name=king +bitmaskindex=14 + +[mod13] +name=placehog +bitmaskindex=15 + +[mod14] +name=sharedammo +bitmaskindex=16 + +[mod15] +name=disablegirders +bitmaskindex=17 + +[mod16] +name=disablelandobjects +bitmaskindex=18 + +[mod17] +name=aisurvival +bitmaskindex=19 + +[mod18] +name=infattack +bitmaskindex=20 + +[mod19] +name=resetweps +bitmaskindex=21 + +[mod20] +name=perhogammo +bitmaskindex=22 + +[mod21] +name=disablewind +bitmaskindex=23 + +[mod22] +name=morewind +bitmaskindex=24 + +[mod23] +name=tagteam +bitmaskindex=25 + +[mod24] +name=bottomborder +bitmaskindex=26 + + +[setting0] +name=damagefactor +times1000=false +command=e$damagepct +maxmeansinfinity=false +min=10 +max=300 +default=100 + +[setting1] +name=turntime +times1000=true +command=e$turntime +maxmeansinfinity=true +min=1 +max=9999 +default=45 + +[setting2] +name=health +times1000=false +maxmeansinfinity=false +min=50 +max=200 +default=100 + +[setting3] +name=suddendeath +times1000=false +command=e$sd_turns +maxmeansinfinity=true +min=0 +max=50 +default=15 + +[setting4] +name=caseprobability +times1000=false +command=e$casefreq +maxmeansinfinity=false +min=0 +max=9 +default=5 + +[setting5] +name=minestime +times1000=true +command=e$minestime +maxmeansinfinity=false +min=-1 +max=5 +default=3 + +[setting6] +name=minesnum +times1000=false +command=e$minesnum +maxmeansinfinity=false +min=0 +max=80 +default=4 + +[setting7] +name=minedudpct +times1000=false +command=e$minedudpct +maxmeansinfinity=false +min=0 +max=100 +default=0 + +[setting8] +name=explosives +times1000=false +command=e$explosives +maxmeansinfinity=false +min=0 +max=40 +default=2 + +[setting9] +name=healthprobability +times1000=false +command=e$healthprob +maxmeansinfinity=false +min=0 +max=100 +default=35 + +[setting10] +name=healthcaseamount +times1000=false +command=e$hcaseamount +maxmeansinfinity=false +min=0 +max=200 +default=25 + +[setting11] +name=waterrise +times1000=false +command=e$waterrise +maxmeansinfinity=false +min=0 +max=100 +default=47 + +[setting12] +name=healthdecrease +times1000=false +command=e$healthdec +maxmeansinfinity=false +min=0 +max=100 +default=5 + +[setting13] +name=ropepct +times1000=false +command=e$ropepct +maxmeansinfinity=false +min=25 +max=999 +default=100 + +[setting14] +name=getawaytime +times1000=false +command=e$getawaytime +maxmeansinfinity=false +min=0 +max=999 +default=100 diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/test.c --- a/project_files/frontlib/test.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/test.c Fri Jun 15 19:57:25 2012 +0200 @@ -1,6 +1,8 @@ #include "frontlib.h" #include "util/logging.h" #include "model/map.h" +#include "model/weapon.h" +#include "model/schemelist.h" #include "ipc/mapconn.h" #include "ipc/gameconn.h" @@ -80,7 +82,7 @@ assert(mapConnection); // We don't need the map description anymore - flib_map_destroy(map); + flib_map_release(map); map = NULL; // Register the callback functions @@ -99,10 +101,13 @@ } void testGame() { - flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("basicsettings.ini", "gamemods.ini"); + flib_cfg_meta *metaconf = flib_cfg_meta_from_ini("metasettings.ini"); assert(metaconf); + flib_weaponset *weapons = flib_weaponset_create("Defaultweaps"); + flib_schemelist *schemelist = flib_schemelist_from_ini(metaconf, "schemes.ini"); + flib_gamesetup setup; - setup.gamescheme = flib_cfg_from_ini(metaconf, "scheme_shoppa.ini"); + setup.gamescheme = flib_schemelist_find(schemelist, "Default"); setup.map = flib_map_create_maze("Jungle", MAZE_SIZE_MEDIUM_TUNNELS); setup.seed = "asparagus"; setup.script = NULL; @@ -116,7 +121,6 @@ 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; @@ -126,15 +130,17 @@ setup.teams[0]->hogs[1].initialHealth = 100; setup.teams[0]->hogs[1].name = "Chefkoch"; setup.teams[1] = flib_team_from_ini("Cave Dwellers.hwt"); - setup.teams[1]->color = 0xff0000ff; + setup.teams[1]->color = 0xFF0000F0; setup.teams[1]->hogsInGame = 8; - setup.teams[1]->weaponset = flib_weaponset_create("Defaultweaps"); + flib_team_set_weaponset(setup.teams[0], weapons); + flib_team_set_weaponset(setup.teams[1], weapons); + flib_weaponset_release(weapons); - flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false); + flib_gameconn *gameconn = flib_gameconn_create("Medo42", &setup, false); assert(gameconn); flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn); - flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); + //flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn); startEngineGame(flib_gameconn_getport(gameconn)); @@ -196,7 +202,20 @@ //testMapPreview(); //testDemo(); //testSave(); - testGame(); + //testGame(); + + flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini"); + assert(meta); + flib_schemelist *schemelist = flib_schemelist_from_ini(meta, "schemes.ini"); + assert(schemelist); + + flib_schemelist_to_ini("Copy of Schemelist.ini", schemelist); + flib_schemelist_release(schemelist); + flib_cfg_meta_release(meta); + + flib_weaponsetlist *weaponsets = flib_weaponsetlist_from_ini("weapons.ini"); + assert(!flib_weaponsetlist_to_ini("copy of weapons.ini", weaponsets)); + flib_weaponsetlist_release(weaponsets); flib_quit(); return 0; diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/util/inihelper.c --- a/project_files/frontlib/util/inihelper.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/util/inihelper.c Fri Jun 15 19:57:25 2012 +0200 @@ -179,7 +179,7 @@ value = def; } char *valueDup = flib_strdupnull(value); - if(valueDup) { + if(valueDup || !def) { *outVar = valueDup; result = 0; } @@ -209,7 +209,7 @@ int result = flib_ini_get_int(ini, &tmpValue, key); if(result == 0) { *outVar = tmpValue; - } else if(result == INI_ERROR_NOTFOUND) { + } else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) { *outVar = def; result = 0; } @@ -238,7 +238,7 @@ int result = flib_ini_get_bool(ini, &tmpValue, key); if(result == 0) { *outVar = tmpValue; - } else if(result == INI_ERROR_NOTFOUND) { + } else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) { *outVar = def; result = 0; } diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/util/refcounter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/util/refcounter.h Fri Jun 15 19:57:25 2012 +0200 @@ -0,0 +1,51 @@ +/** + * Helper functions for reference counted structs. + * + * We don't have enough of them to justify going crazy with macros, but I still prefer + * to have the logic in one place. + * + * In particular, these functions handle counter overflow in a sensible way + * (log and leak). + */ + +#ifndef REFCOUNTER_H_ +#define REFCOUNTER_H_ + +#include "logging.h" +#include + +static inline void flib_retain(int *referenceCountPtr, const char *objName) { + if(!referenceCountPtr || !objName) { + flib_log_e("null parameter to flib_retain"); + } else { + if((*referenceCountPtr) >= 0) { + (*referenceCountPtr)++; + flib_log_d("retaining %s, now %i references", objName, (*referenceCountPtr)); + } + if((*referenceCountPtr) < 0) { + flib_log_e("Memory leak: Reference count overflow in %s object!", objName); + } + } +} + +/** + * Returns true if the struct should be freed. + */ +static inline bool flib_release(int *referenceCountPtr, const char *objName) { + bool result = false; + if(!referenceCountPtr) { + flib_log_e("null parameter to flib_release"); + } else if((*referenceCountPtr) > 0) { + if(--(*referenceCountPtr) == 0) { + flib_log_d("releasing and destroying %s", objName); + result = true; + } else { + flib_log_d("releasing %s, now %i references", objName, (*referenceCountPtr)); + } + } else if((*referenceCountPtr) == 0) { + flib_log_e("Attempt to release a %s with zero references!", objName); + } + return result; +} + +#endif /* REFCOUNTER_H_ */ diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/util/util.c --- a/project_files/frontlib/util/util.c Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/util/util.c Fri Jun 15 19:57:25 2012 +0200 @@ -56,7 +56,7 @@ void *flib_malloc(size_t size) { void *result = malloc(size); - if(!result) { + if(!result && size>0) { flib_log_e("Out of memory trying to malloc %zu bytes.", size); } return result; @@ -64,17 +64,29 @@ void *flib_calloc(size_t count, size_t elementsize) { void *result = calloc(count, elementsize); - if(!result) { + if(!result && count>0 && elementsize>0) { flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize); } return result; } +void *flib_realloc(void *ptr, size_t size) { + void *result = realloc(ptr, size); + if(!result && size>0) { + flib_log_e("Out of memory trying to realloc %zu bytes.", size); + } + return result; +} + static bool isAsciiAlnum(char c) { return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z'); } char *flib_urlencode(const char *inbuf) { + return flib_urlencode_pred(inbuf, isAsciiAlnum); +} + +char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) { if(!inbuf) { return NULL; } @@ -91,7 +103,7 @@ size_t inpos = 0, outpos = 0; while(inbuf[inpos]) { - if(isAsciiAlnum(inbuf[inpos])) { + if(!needsEscaping(inbuf[inpos])) { outbuf[outpos++] = inbuf[inpos++]; } else { if(snprintf(outbuf+outpos, 4, "%%%02X", (unsigned)((uint8_t*)inbuf)[inpos])<0) { diff -r 1c859f572d72 -r 240620f46dd7 project_files/frontlib/util/util.h --- a/project_files/frontlib/util/util.h Tue Jun 12 21:10:11 2012 +0200 +++ b/project_files/frontlib/util/util.h Fri Jun 15 19:57:25 2012 +0200 @@ -3,6 +3,7 @@ #include #include +#include /** * Prints a format string to a newly allocated buffer of the required size. @@ -46,6 +47,12 @@ void *flib_calloc(size_t count, size_t elementsize); /** + * Simple realloc wrapper that automatically logs an error if no memory + * is available. Otherwise behaves exactly like realloc. + */ +void *flib_realloc(void *ptr, size_t size); + +/** * Replace all non-alphanumeric and non-ascii bytes with escape * sequences in the form %XX. Does not modify the original string, * but returns a newly allocated one that must be free()d. Returns @@ -56,6 +63,17 @@ char *flib_urlencode(const char *str); /** + * Replace some bytes with escape sequences in the form %XX. + * Does not modify the original string, but returns a newly allocated + * one that must be free()d. + * + * All bytes for which the predicate function returns true are escaped. + * + * Returns null on failure or if null was passed as argument. + */ +char *flib_urlencode_pred(const char *str, bool (*needsEscaping)(char c)); + +/** * Replace escape sequences of the form %XX with their byte values. * Does not modify the original string, but returns a newly allocated * one that must be free()d. Returns null on failure or if null was