Implemented game launching API for the frontlib.
It is still buggy though, and not all game settings can be conveniently created/modified yet.
--- 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 <stdlib.h>
-#include <limits.h>
-#include <string.h>
-
-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;
-}
--- 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 <stdint.h>
-#include <stddef.h>
-
-/**
- * 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
--- 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 <SDL.h>
#include <SDL_net.h>
@@ -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<MAPIMAGE_HEIGHT; y++) {
- for(int x=0; x<MAPIMAGE_WIDTH; x++) {
- if(bitmap[pixelnum>>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();
--- 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"
--- 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 <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdarg.h>
-
-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(val<INT_MIN || val>INT_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;
-}
--- 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 <stdbool.h>
-
-/**
- * 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_ */
--- 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 <stdbool.h>
-#include <stdlib.h>
-
-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);
-}
--- 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 <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-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_ */
--- 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 <stdbool.h>
#include <stdio.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.
--- /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 <stdbool.h>
+#include <stdlib.h>
+
+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; i<meta->modCount; 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; i<setup->teamcount; 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);
+ }
+ }
+}
--- /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 <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#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
--- 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 <string.h>
#include <stdbool.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 <stddef.h>
#include <stdbool.h>
@@ -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.
*
--- 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 <stdio.h>
#include <stdbool.h>
#include <string.h>
+#include <inttypes.h>
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; i<meta->modCount; i++) {
+ if(scheme->mods[i]) {
+ gamemods |= (1<<meta->mods[i].bitmaskIndex);
+ }
+ }
+ error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, gamemods);
+ for(int i=0; i<meta->settingCount; 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; i<team->hogsInGame; 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;
+}
--- 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 <stdbool.h>
@@ -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_ */
--- 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 <stdlib.h>
@@ -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;
--- 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 <stdint.h>
#define MAPIMAGE_WIDTH 256
--- 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 <time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-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);
-}
--- 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<stdint.h>
-
-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_ */
--- 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 <stdio.h>
--- /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"
+
--- /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
--- 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 <stdlib.h>
--- /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"
--- /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 <stdbool.h>
+#include <stdint.h>
+
+#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_ */
--- 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 <stdlib.h>
#include <ctype.h>
--- 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 <stdlib.h>
#include <SDL_net.h>
#include <time.h>
--- 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 <stddef.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-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;
-}
--- 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 <stddef.h>
-#include <stdarg.h>
-
-/**
- * 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
--- /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 <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+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;
+}
--- /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 <stdint.h>
+#include <stddef.h>
+
+/**
+ * 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
--- /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 <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdarg.h>
+
+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(val<INT_MIN || val>INT_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;
+}
--- /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 <stdbool.h>
+
+/**
+ * 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_ */
--- /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 <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+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);
+}
--- /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<stdint.h>
+
+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_ */
--- /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 <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+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;
+}
--- /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 <stddef.h>
+#include <stdarg.h>
+
+/**
+ * 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