--- a/project_files/frontlib/frontlib.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/frontlib.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,21 +1,14 @@
#include "frontlib.h"
#include "util/logging.h"
-#include "model/map.h"
-#include "ipc/mapconn.h"
-#include "ipc/gameconn.h"
-
#include <SDL.h>
#include <SDL_net.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
static int flib_initflags;
int flib_init(int flags) {
flib_initflags = flags;
+ flib_log_d("Initializing frontlib");
if(!(flib_initflags | FRONTLIB_SDL_ALREADY_INITIALIZED)) {
if(SDL_Init(0)==-1) {
flib_log_e("Error in SDL_Init: %s", SDL_GetError());
@@ -35,81 +28,9 @@
}
void flib_quit() {
+ flib_log_d("Shutting down frontlib");
SDLNet_Quit();
if(!(flib_initflags | FRONTLIB_SDL_ALREADY_INITIALIZED)) {
SDL_Quit();
}
}
-
-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 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 *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.script = NULL;
- 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_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false);
- assert(gameconn);
-
- flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn);
- flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn);
-
- while(gameconn) {
- flib_gameconn_tick(gameconn);
- }
- flib_log_i("Shutting down...");
- flib_quit();
- return 0;
-}
--- a/project_files/frontlib/ipc/demo.c Mon Jun 11 00:06:22 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-#include "demo.h"
-#include "../util/logging.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-
-static int demo_record(flib_vector demoBuffer, const void *data, size_t len) {
- if(flib_vector_append(demoBuffer, data, len) < len) {
- flib_log_e("Error recording demo: Out of memory.");
- return -1;
- } else {
- return 0;
- }
-}
-
-int flib_demo_record_from_engine(flib_vector demoBuffer, const uint8_t *message, const char *playerName) {
- if(!demoBuffer || !message || !playerName) {
- flib_log_e("Call to flib_demo_record_from_engine with demoBuffer==null or message==null or playerName==null");
- return -1;
- }
-
- if(strchr("?CEiQqHb", message[1])) {
- return 0; // Those message types are not recorded in a demo.
- }
-
- if(message[1] == 's') {
- if(message[0] >= 3) {
- // Chat messages are reformatted to make them look as if they were received, not sent.
- // Get the actual chat message as C string
- char chatMsg[256];
- memcpy(chatMsg, message+2, message[0]-3);
- chatMsg[message[0]-3] = 0;
-
- // If the message starts with /me, it will be displayed differently.
- char converted[257];
- bool memessage = message[0] >= 7 && !memcmp(message+2, "/me ", 4);
- const char *template = memessage ? "s\x02* %s %s " : "s\x01%s: %s ";
- int size = snprintf(converted+1, 256, template, playerName, chatMsg);
- if(size>0) {
- converted[0] = size>255 ? 255 : size;
- return demo_record(demoBuffer, converted, converted[0]+1);
- } else {
- return 0;
- }
- } else {
- return 0; // Malformed chat message is no reason to abort...
- }
- } else {
- return demo_record(demoBuffer, message, message[0]+1);
- }
-}
-
-int flib_demo_record_to_engine(flib_vector demoBuffer, const uint8_t *message, size_t len) {
- if(!demoBuffer || (len>0 && !message)) {
- flib_log_e("Call to flib_demo_record_to_engine with demoBuffer==null or message==null");
- return -1;
- }
- return demo_record(demoBuffer, message, len);
-}
-
-void flib_demo_replace_gamemode(flib_buffer buf, char gamemode) {
- size_t msgStart = 0;
- char *data = (char*)buf.data;
- while(msgStart+2 < buf.size) {
- if(!memcmp(data+msgStart, "\x02T", 2)) {
- data[msgStart+2] = gamemode;
- }
- msgStart += (uint8_t)data[msgStart]+1;
- }
-}
--- a/project_files/frontlib/ipc/demo.h Mon Jun 11 00:06:22 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/**
- * Demo recording functions. Only used by the ipc game code.
- */
-
-#ifndef DEMO_H_
-#define DEMO_H_
-
-#include "../util/buffer.h"
-
-/**
- * Record a message sent from the engine to the frontend.
- * Returns 0 for OK, a negative value on error.
- * Don't pass NULL.
- */
-int flib_demo_record_from_engine(flib_vector demoBuffer, const uint8_t *message, const char *playerName);
-
-/**
- * Record a message sent from the frontend to the engine.
- * Returns 0 for OK, a negative value on error.
- * Don't pass NULL.
- */
-int flib_demo_record_to_engine(flib_vector demoBuffer, const uint8_t *message, size_t len);
-
-/**
- * Replace game mode messages ("TL", "TD", "TS", "TN") in the recording to mirror
- * the intended use. Pass 'S' for savegames, 'D' for demos.
- */
-void flib_demo_replace_gamemode(flib_buffer buf, char gamemode);
-
-#endif /* DEMO_H_ */
--- a/project_files/frontlib/ipc/gameconn.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.c Tue Jun 12 11:25:05 2012 +0200
@@ -2,9 +2,11 @@
#include "ipcconn.h"
#include "ipcprotocol.h"
#include "../util/logging.h"
+#include "../util/util.h"
#include "../hwconsts.h"
#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
typedef enum {
AWAIT_CONNECTION,
@@ -13,8 +15,10 @@
} gameconn_state;
struct _flib_gameconn {
- flib_ipcconn connection;
- flib_vector configBuffer;
+ flib_ipcconn *connection;
+ flib_vector *configBuffer;
+ flib_vector *demoBuffer;
+ char *playerName;
gameconn_state state;
bool netgame;
@@ -69,7 +73,7 @@
return false;
}
-static int fillConfigBuffer(flib_vector configBuffer, const char *playerName, flib_cfg_meta *metaconf, flib_gamesetup *setup, bool netgame) {
+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;
@@ -89,7 +93,7 @@
}
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_addteam(configBuffer, setup->teams[i], perHogAmmo, sharedAmmo);
}
}
error |= flib_ipc_append_message(configBuffer, "!");
@@ -98,11 +102,15 @@
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));
+ flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
if(tempConn) {
- tempConn->connection = flib_ipcconn_create(record, playerName);
+ tempConn->connection = flib_ipcconn_create();
tempConn->configBuffer = flib_vector_create();
- if(tempConn->connection && tempConn->configBuffer) {
+ tempConn->playerName = flib_strdupnull(playerName);
+ if(tempConn->connection && tempConn->configBuffer && tempConn->playerName) {
+ if(record) {
+ tempConn->demoBuffer = flib_vector_create();
+ }
tempConn->state = AWAIT_CONNECTION;
tempConn->netgame = netGame;
clearCallbacks(tempConn);
@@ -164,8 +172,10 @@
clearCallbacks(conn);
conn->destroyRequested = true;
} else {
- flib_ipcconn_destroy(&conn->connection);
- flib_vector_destroy(&conn->configBuffer);
+ flib_ipcconn_destroy(conn->connection);
+ flib_vector_destroy(conn->configBuffer);
+ flib_vector_destroy(conn->demoBuffer);
+ free(conn->playerName);
free(conn);
}
}
@@ -180,6 +190,93 @@
}
}
+static void demo_append(flib_gameconn *conn, const void *data, size_t len) {
+ if(conn->demoBuffer) {
+ if(flib_vector_append(conn->demoBuffer, data, len) < len) {
+ flib_log_e("Error recording demo: Out of memory.");
+ flib_vector_destroy(conn->demoBuffer);
+ conn->demoBuffer = NULL;
+ }
+ }
+}
+
+static int format_chatmessage(uint8_t buffer[257], const char *playerName, const char *message) {
+ size_t msglen = strlen(message);
+
+ // If the message starts with /me, it will be displayed differently.
+ bool meMessage = msglen >= 4 && !memcmp(message, "/me ", 4);
+ const char *template = meMessage ? "s\x02* %s %s " : "s\x01%s: %s ";
+ int size = snprintf((char*)buffer+1, 256, template, playerName, meMessage ? message+4 : message);
+ if(size>0) {
+ buffer[0] = size>255 ? 255 : size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static void demo_append_chatmessage(flib_gameconn *conn, const char *message) {
+ // Chat messages are reformatted to make them look as if they were received, not sent.
+ uint8_t converted[257];
+ if(!format_chatmessage(converted, conn->playerName, message)) {
+ demo_append(conn, converted, converted[0]+1);
+ }
+}
+
+static void demo_replace_gamemode(flib_buffer buf, char gamemode) {
+ size_t msgStart = 0;
+ uint8_t *data = (uint8_t*)buf.data;
+ while(msgStart+2 < buf.size) {
+ if(!memcmp(data+msgStart, "\x02T", 2)) {
+ data[msgStart+2] = gamemode;
+ }
+ msgStart += (uint8_t)data[msgStart]+1;
+ }
+}
+
+int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len) {
+ int result = -1;
+ if(!conn || (!data && len>0)) {
+ flib_log_e("null parameter in flib_gameconn_send_enginemsg");
+ } else if(!flib_ipcconn_send_raw(conn->connection, data, len)) {
+ demo_append(conn, data, len);
+ result = 0;
+ }
+ return result;
+}
+
+int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg) {
+ int result = -1;
+ if(!conn || !msg) {
+ flib_log_e("null parameter in flib_gameconn_send_textmsg");
+ } else {
+ uint8_t converted[257];
+ int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg);
+ if(size>0) {
+ converted[0] = size>255 ? 255 : size;
+ if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) {
+ demo_append(conn, converted, converted[0]+1);
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
+
+int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg) {
+ int result = -1;
+ uint8_t converted[257];
+ if(!conn || !playername || !msg) {
+ flib_log_e("null parameter in flib_gameconn_send_chatmsg");
+ } else if(format_chatmessage(converted, playername, msg)) {
+ flib_log_e("Error formatting message in flib_gameconn_send_chatmsg");
+ } else if(!flib_ipcconn_send_raw(conn->connection, converted, converted[0]+1)) {
+ demo_append(conn, converted, converted[0]+1);
+ result = 0;
+ }
+ return result;
+}
+
void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context) {
if(!conn) {
flib_log_e("null parameter in flib_gameconn_onConnect");
@@ -246,6 +343,7 @@
conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
return;
} else {
+ demo_append(conn, configBuffer.data, configBuffer.size);
conn->state = CONNECTED;
conn->onConnectCb(conn->onConnectCtx);
if(conn->destroyRequested) {
@@ -272,30 +370,31 @@
continue;
}
switch(msgbuffer[1]) {
- case '?':
+ case '?': // Ping
// The pong is already part of the config message
break;
- case 'C':
+ case 'C': // Config query
// And we already send the config message on connecting.
break;
- case 'E':
+ case 'E': // Error message
if(len>=3) {
msgbuffer[len-2] = 0;
conn->onErrorMessageCb(conn->onErrorMessageCtx, (char*)msgbuffer+2);
}
break;
- case 'i':
+ case 'i': // Statistics
// TODO stats
break;
- case 'Q':
- case 'H':
- case 'q':
+ case 'Q': // Game interrupted
+ case 'H': // Game halted
+ case 'q': // game finished
{
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->demoBuffer) {
+ flib_buffer demoBuffer = flib_vector_as_buffer(conn->demoBuffer);
+ demo_replace_gamemode(demoBuffer, savegame ? 'S' : 'D');
+ conn->onGameRecordedCb(conn->onGameRecordedCtx, demoBuffer.data, demoBuffer.size, savegame);
if(conn->destroyRequested) {
return;
}
@@ -304,19 +403,23 @@
conn->onDisconnectCb(conn->onDisconnectCtx, reason);
return;
}
- case 's':
+ case 's': // Chat message
if(len>=3) {
msgbuffer[len-2] = 0;
+ demo_append_chatmessage(conn, (char*)msgbuffer+2);
+
conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, false);
}
break;
- case 'b':
+ case 'b': // Teamchat message
if(len>=3) {
msgbuffer[len-2] = 0;
conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, true);
}
break;
- default:
+ default: // Engine message
+ demo_append(conn, msgbuffer, len);
+
conn->onNetMessageCb(conn->onNetMessageCtx, msgbuffer, len);
break;
}
--- a/project_files/frontlib/ipc/gameconn.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/gameconn.h Tue Jun 12 11:25:05 2012 +0200
@@ -33,12 +33,9 @@
*/
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);
-*/
+int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len);
+int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg);
+int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg);
/**
* handleConnect(void *context)
--- a/project_files/frontlib/ipc/ipcconn.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/ipcconn.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,6 +1,6 @@
#include "ipcconn.h"
-#include "demo.h"
#include "../util/logging.h"
+#include "../util/util.h"
#include "../socket.h"
#include <string.h>
@@ -17,25 +17,21 @@
*/
typedef struct _flib_ipcconn {
uint8_t readBuffer[8192];
- char playerName[256];
-
int readBufferSize;
- flib_acceptor acceptor;
+ flib_acceptor *acceptor;
uint16_t port;
- flib_tcpsocket sock;
- flib_vector demoBuffer;
+ flib_tcpsocket *sock;
} _flib_ipcconn;
-flib_ipcconn flib_ipcconn_create(bool recordDemo, const char *localPlayerName) {
- flib_ipcconn result = malloc(sizeof(_flib_ipcconn));
- flib_acceptor acceptor = flib_acceptor_create(0);
+flib_ipcconn *flib_ipcconn_create() {
+ flib_ipcconn *result = flib_malloc(sizeof(_flib_ipcconn));
+ flib_acceptor *acceptor = flib_acceptor_create(0);
if(!result || !acceptor) {
- flib_log_e("Can't create ipcconn.");
free(result);
- flib_acceptor_close(&acceptor);
+ flib_acceptor_close(acceptor);
return NULL;
}
@@ -44,44 +40,29 @@
result->readBufferSize = 0;
result->port = flib_acceptor_listenport(acceptor);
- if(localPlayerName) {
- strncpy(result->playerName, localPlayerName, 255);
- } else {
- strncpy(result->playerName, "Player", 255);
- }
-
- if(recordDemo) {
- result->demoBuffer = flib_vector_create();
- }
-
flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port);
return result;
}
-uint16_t flib_ipcconn_port(flib_ipcconn ipc) {
+uint16_t flib_ipcconn_port(flib_ipcconn *ipc) {
if(!ipc) {
- flib_log_e("Call to flib_ipcconn_port with ipc==null");
+ flib_log_e("null parameter in flib_ipcconn_port");
return 0;
}
return ipc->port;
}
-void flib_ipcconn_destroy(flib_ipcconn *ipcptr) {
- if(!ipcptr) {
- flib_log_e("Call to flib_ipcconn_destroy with ipcptr==null");
- } else if(*ipcptr) {
- flib_ipcconn ipc = *ipcptr;
- flib_acceptor_close(&ipc->acceptor);
- flib_socket_close(&ipc->sock);
- flib_vector_destroy(&ipc->demoBuffer);
+void flib_ipcconn_destroy(flib_ipcconn *ipc) {
+ if(ipc) {
+ flib_acceptor_close(ipc->acceptor);
+ flib_socket_close(ipc->sock);
free(ipc);
- *ipcptr = NULL;
}
}
-IpcConnState flib_ipcconn_state(flib_ipcconn ipc) {
+IpcConnState flib_ipcconn_state(flib_ipcconn *ipc) {
if(!ipc) {
- flib_log_e("Call to flib_ipcconn_state with ipc==null");
+ flib_log_e("null parameter in flib_ipcconn_state");
return IPC_NOT_CONNECTED;
} else if(ipc->sock) {
return IPC_CONNECTED;
@@ -92,24 +73,25 @@
}
}
-static bool isMessageReady(flib_ipcconn ipc) {
+static bool isMessageReady(flib_ipcconn *ipc) {
return ipc->readBufferSize >= ipc->readBuffer[0]+1;
}
-static void receiveToBuffer(flib_ipcconn ipc) {
+static void receiveToBuffer(flib_ipcconn *ipc) {
if(ipc->sock) {
int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize);
if(size>=0) {
ipc->readBufferSize += size;
} else {
- flib_socket_close(&ipc->sock);
+ flib_socket_close(ipc->sock);
+ ipc->sock = NULL;
}
}
}
-int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data) {
+int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data) {
if(!ipc || !data) {
- flib_log_e("Call to flib_ipcconn_recv_message with ipc==null or data==null");
+ flib_log_e("null parameter in flib_ipcconn_recv_message");
return -1;
}
@@ -118,12 +100,6 @@
}
if(isMessageReady(ipc)) {
- if(ipc->demoBuffer) {
- if(flib_demo_record_from_engine(ipc->demoBuffer, ipc->readBuffer, ipc->playerName) < 0) {
- flib_log_w("Stopping demo recording due to an error.");
- flib_vector_destroy(&ipc->demoBuffer);
- }
- }
int msgsize = ipc->readBuffer[0]+1;
memcpy(data, ipc->readBuffer, msgsize);
memmove(ipc->readBuffer, ipc->readBuffer+msgsize, ipc->readBufferSize-msgsize);
@@ -138,9 +114,9 @@
}
}
-int flib_ipcconn_recv_map(flib_ipcconn ipc, void *data) {
+int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data) {
if(!ipc || !data) {
- flib_log_e("Call to flib_ipcconn_recv_map with ipc==null or data==null");
+ flib_log_e("null parameter in flib_ipcconn_recv_map");
return -1;
}
@@ -156,7 +132,7 @@
}
static void logSentMsg(const uint8_t *data, size_t len) {
- if(flib_log_getLevel() > FLIB_LOGLEVEL_DEBUG) {
+ if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
size_t msgStart = 0;
while(msgStart < len) {
uint8_t msglen = data[msgStart];
@@ -171,9 +147,9 @@
}
}
-int flib_ipcconn_send_raw(flib_ipcconn ipc, const void *data, size_t len) {
+int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len) {
if(!ipc || (!data && len>0)) {
- flib_log_e("Call to flib_ipcconn_send_raw with ipc==null or data==null");
+ flib_log_e("null parameter in flib_ipcconn_send_raw");
return -1;
}
if(!ipc->sock) {
@@ -183,23 +159,21 @@
if(flib_socket_send(ipc->sock, data, len) == len) {
logSentMsg(data, len);
- if(ipc->demoBuffer) {
- if(flib_demo_record_to_engine(ipc->demoBuffer, data, len) < 0) {
- flib_log_w("Stopping demo recording due to an error.");
- flib_vector_destroy(&ipc->demoBuffer);
- }
- }
return 0;
} else {
flib_log_w("Failed or incomplete ICP write: engine connection lost.");
- flib_socket_close(&ipc->sock);
+ flib_socket_close(ipc->sock);
+ ipc->sock = NULL;
return -1;
}
}
-int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len) {
- if(!ipc || (!data && len>0) || len>255) {
- flib_log_e("Call to flib_ipcconn_send_message with ipc==null or data==null or len>255");
+int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len) {
+ if(!ipc || (!data && len>0)) {
+ flib_log_e("null parameter in flib_ipcconn_send_message");
+ return -1;
+ } else if(len>255) {
+ flib_log_e("Overlong message (%zu bytes) in flib_ipcconn_send_message", len);
return -1;
}
@@ -209,29 +183,18 @@
return flib_ipcconn_send_raw(ipc, sendbuf, len+1);
}
-int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data) {
+int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data) {
return flib_ipcconn_send_message(ipc, data, strlen(data));
}
-void flib_ipcconn_accept(flib_ipcconn ipc) {
+void flib_ipcconn_accept(flib_ipcconn *ipc) {
if(!ipc) {
- flib_log_e("Call to flib_ipcconn_accept with ipc==null");
+ flib_log_e("null parameter in flib_ipcconn_accept");
} else if(!ipc->sock && ipc->acceptor) {
ipc->sock = flib_socket_accept(ipc->acceptor, true);
if(ipc->sock) {
- flib_acceptor_close(&ipc->acceptor);
+ flib_acceptor_close(ipc->acceptor);
+ ipc->acceptor = NULL;
}
}
}
-
-flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save) {
- if(!ipc) {
- flib_log_e("Call to flib_ipcconn_getrecord with ipc==null");
- }
- if(!ipc || !ipc->demoBuffer) {
- flib_constbuffer result = {NULL, 0};
- return result;
- }
- flib_demo_replace_gamemode(flib_vector_as_buffer(ipc->demoBuffer), save ? 'S' : 'D');
- return flib_vector_as_constbuffer(ipc->demoBuffer);
-}
--- a/project_files/frontlib/ipc/ipcconn.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/ipcconn.h Tue Jun 12 11:25:05 2012 +0200
@@ -15,11 +15,9 @@
typedef enum {IPC_NOT_CONNECTED, IPC_LISTENING, IPC_CONNECTED} IpcConnState;
struct _flib_ipcconn;
-typedef struct _flib_ipcconn *flib_ipcconn;
+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.
*
@@ -32,19 +30,19 @@
* We stop accepting new connections once a connection has been established, so you
* need to create a new ipcconn in order to start a new connection.
*/
-flib_ipcconn flib_ipcconn_create(bool recordDemo, const char *localPlayerName);
+flib_ipcconn *flib_ipcconn_create();
-uint16_t flib_ipcconn_port(flib_ipcconn ipc);
+uint16_t flib_ipcconn_port(flib_ipcconn *ipc);
/**
- * Free resources, close sockets, and set the pointer to NULL.
+ * Free resources and close sockets.
*/
-void flib_ipcconn_destroy(flib_ipcconn *ipcptr);
+void flib_ipcconn_destroy(flib_ipcconn *ipc);
/**
* Determine the current connection state
*/
-IpcConnState flib_ipcconn_state(flib_ipcconn ipc);
+IpcConnState flib_ipcconn_state(flib_ipcconn *ipc);
/**
* Receive a single message (up to 256 bytes) and copy it into the data buffer.
@@ -58,7 +56,7 @@
* no further message is returned, to ensure you see all messages that were sent
* before the connection closed.
*/
-int flib_ipcconn_recv_message(flib_ipcconn ipc, void *data);
+int flib_ipcconn_recv_message(flib_ipcconn *ipc, void *data);
/**
* Try to receive 4097 bytes. This is the size of the reply the engine sends
@@ -66,9 +64,9 @@
* twocolor image of the map (256x128), the last byte is the number of hogs that
* fit on the map.
*/
-int flib_ipcconn_recv_map(flib_ipcconn ipc, void *data);
+int flib_ipcconn_recv_map(flib_ipcconn *ipc, void *data);
-int flib_ipcconn_send_raw(flib_ipcconn ipc, const void *data, size_t len);
+int flib_ipcconn_send_raw(flib_ipcconn *ipc, const void *data, size_t len);
/**
* Write a single message (up to 255 bytes) to the engine. This call blocks until the
@@ -77,32 +75,17 @@
* Calling this function in a state other than IPC_CONNECTED will fail immediately.
* Returns a negative value on failure.
*/
-int flib_ipcconn_send_message(flib_ipcconn ipc, void *data, size_t len);
+int flib_ipcconn_send_message(flib_ipcconn *ipc, void *data, size_t len);
/**
* Convenience function for sending a 0-delimited string.
*/
-int flib_ipcconn_send_messagestr(flib_ipcconn ipc, char *data);
+int flib_ipcconn_send_messagestr(flib_ipcconn *ipc, char *data);
/**
* Call regularly to allow background work to proceed
*/
-void flib_ipcconn_accept(flib_ipcconn ipc);
-
-/**
- * Get a record of the connection. This should be called after
- * the connection is closed and all messages have been received.
- *
- * If demo recording was not enabled, or if the recording failed for some reason,
- * the buffer will be empty.
- *
- * If save=true is passed, the result will be a savegame, otherwise it will be a
- * demo.
- *
- * The buffer is only valid until flib_ipcconn_getsave is called again or the ipcconn
- * is destroyed.
- */
-flib_constbuffer flib_ipcconn_getrecord(flib_ipcconn ipc, bool save);
+void flib_ipcconn_accept(flib_ipcconn *ipc);
#endif /* IPCCONN_H_ */
--- a/project_files/frontlib/ipc/ipcprotocol.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/ipcprotocol.c Tue Jun 12 11:25:05 2012 +0200
@@ -7,7 +7,7 @@
#include <string.h>
#include <inttypes.h>
-int flib_ipc_append_message(flib_vector vec, const char *fmt, ...) {
+int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) {
int result = -1;
if(!vec || !fmt) {
flib_log_e("null parameter in flib_ipc_appendmessage");
@@ -38,9 +38,9 @@
return result;
}
-int flib_ipc_append_mapconf(flib_vector vec, flib_map *map, bool mappreview) {
+int flib_ipc_append_mapconf(flib_vector *vec, flib_map *map, bool mappreview) {
int result = -1;
- flib_vector tempvector = flib_vector_create();
+ flib_vector *tempvector = flib_vector_create();
if(!vec || !map) {
flib_log_e("null parameter in flib_ipc_append_mapconf");
} else if(tempvector) {
@@ -83,11 +83,11 @@
}
}
}
- flib_vector_destroy(&tempvector);
+ flib_vector_destroy(tempvector);
return result;
}
-int flib_ipc_append_seed(flib_vector vec, const char *seed) {
+int flib_ipc_append_seed(flib_vector *vec, const char *seed) {
if(!vec || !seed) {
flib_log_e("null parameter in flib_ipc_append_seed");
return -1;
@@ -96,9 +96,9 @@
}
}
-int flib_ipc_append_gamescheme(flib_vector vec, flib_cfg *scheme, flib_cfg_meta *meta) {
+int flib_ipc_append_gamescheme(flib_vector *vec, flib_cfg *scheme, flib_cfg_meta *meta) {
int result = -1;
- flib_vector tempvector = flib_vector_create();
+ flib_vector *tempvector = flib_vector_create();
if(!vec || !scheme || !meta) {
flib_log_e("null parameter in flib_ipc_append_gamescheme");
} else if(tempvector) {
@@ -129,14 +129,14 @@
}
}
}
- flib_vector_destroy(&tempvector);
+ 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 flib_ipc_append_addteam(flib_vector *vec, flib_team *team, bool perHogAmmo, bool sharedAmmo) {
int result = -1;
- flib_vector tempvector = flib_vector_create();
+ flib_vector *tempvector = flib_vector_create();
if(!vec || !team || !team->weaponset) {
flib_log_e("invalid parameter in flib_ipc_append_addteam");
} else if(tempvector) {
@@ -161,7 +161,9 @@
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->bindingCount; i++) {
+ error |= flib_ipc_append_message(tempvector, "ebind %s %s", team->bindings[i].binding, team->bindings[i].action);
+ }
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);
@@ -176,6 +178,6 @@
}
}
}
- flib_vector_destroy(&tempvector);
+ flib_vector_destroy(tempvector);
return result;
}
--- a/project_files/frontlib/ipc/ipcprotocol.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/ipcprotocol.h Tue Jun 12 11:25:05 2012 +0200
@@ -15,7 +15,7 @@
* Returns nonzero if something goes wrong. In that case the buffer
* contents are unaffected.
*/
-int flib_ipc_append_message(flib_vector vec, const char *fmt, ...);
+int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...);
/**
* Append IPC messages to the buffer that configure the engine for
@@ -27,7 +27,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, flib_map *map, bool mappreview);
/**
* Append a seed message to the buffer.
@@ -35,7 +35,7 @@
* Returns nonzero if something goes wrong. In that case the buffer
* contents are unaffected.
*/
-int flib_ipc_append_seed(flib_vector vec, const char *seed);
+int flib_ipc_append_seed(flib_vector *vec, const char *seed);
/**
* Append the game scheme to the buffer.
@@ -43,8 +43,8 @@
* 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, flib_cfg *seed, flib_cfg_meta *meta);
-int flib_ipc_append_addteam(flib_vector vec, flib_team *team, bool perHogAmmo, bool sharedAmmo);
+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 Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/ipc/mapconn.c Tue Jun 12 11:25:05 2012 +0200
@@ -4,6 +4,7 @@
#include "../util/logging.h"
#include "../util/buffer.h"
+#include "../util/util.h"
#include <stdlib.h>
@@ -15,8 +16,8 @@
struct _flib_mapconn {
uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES];
- flib_ipcconn connection;
- flib_vector configBuffer;
+ flib_ipcconn *connection;
+ flib_vector *configBuffer;
mapconn_state progress;
@@ -38,9 +39,9 @@
conn->onFailureCb = &noop_handleFailure;
}
-static flib_vector createConfigBuffer(char *seed, flib_map *mapdesc) {
- flib_vector result = NULL;
- flib_vector tempbuffer = flib_vector_create();
+static flib_vector *createConfigBuffer(char *seed, flib_map *mapdesc) {
+ flib_vector *result = NULL;
+ flib_vector *tempbuffer = flib_vector_create();
if(tempbuffer) {
bool error = false;
error |= flib_ipc_append_seed(tempbuffer, seed);
@@ -51,15 +52,15 @@
tempbuffer = NULL;
}
}
- flib_vector_destroy(&tempbuffer);
+ flib_vector_destroy(tempbuffer);
return result;
}
flib_mapconn *flib_mapconn_create(char *seed, flib_map *mapdesc) {
flib_mapconn *result = NULL;
- flib_mapconn *tempConn = calloc(1, sizeof(flib_mapconn));
+ flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn));
if(tempConn) {
- tempConn->connection = flib_ipcconn_create(false, "Player");
+ tempConn->connection = flib_ipcconn_create();
tempConn->configBuffer = createConfigBuffer(seed, mapdesc);
if(tempConn->connection && tempConn->configBuffer) {
tempConn->progress = AWAIT_CONNECTION;
@@ -83,8 +84,8 @@
clearCallbacks(conn);
conn->destroyRequested = true;
} else {
- flib_ipcconn_destroy(&conn->connection);
- flib_vector_destroy(&conn->configBuffer);
+ flib_ipcconn_destroy(conn->connection);
+ flib_vector_destroy(conn->configBuffer);
free(conn);
}
}
--- a/project_files/frontlib/model/cfg.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/cfg.c Tue Jun 12 11:25:05 2012 +0200
@@ -8,7 +8,78 @@
#include <stdio.h>
-static void freeCfgMeta(flib_cfg_meta *cfg) {
+static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, dictionary *settingfile, dictionary *modfile) {
+ flib_cfg_meta_destroy(result);
+ iniparser_freedict(settingfile);
+ iniparser_freedict(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));
+ dictionary *settingfile = iniparser_load(settingpath);
+ dictionary *modfile = iniparser_load(modpath);
+
+ if(!result || !settingfile || !modfile) {
+ return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
+ }
+
+ result->settingCount = iniparser_getnsec(settingfile);
+ result->modCount = iniparser_getnsec(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; i<result->settingCount; i++) {
+ char *sectionName = iniparser_getsecname(settingfile, i);
+ if(!sectionName) {
+ return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
+ }
+
+ bool error = false;
+ result->settings[i].iniName = flib_strdupnull(sectionName);
+ result->settings[i].title = inihelper_getstringdup(settingfile, &error, sectionName, "title");
+ result->settings[i].engineCommand = inihelper_getstringdup(settingfile, &error, sectionName, "command");
+ result->settings[i].image = inihelper_getstringdup(settingfile, &error, sectionName, "image");
+ result->settings[i].checkOverMax = inihelper_getbool(settingfile, &error, sectionName, "checkOverMax");
+ result->settings[i].times1000 = inihelper_getbool(settingfile, &error, sectionName, "times1000");
+ result->settings[i].min = inihelper_getint(settingfile, &error, sectionName, "min");
+ result->settings[i].max = inihelper_getint(settingfile, &error, sectionName, "max");
+ result->settings[i].def = inihelper_getint(settingfile, &error, sectionName, "default");
+ if(error) {
+ flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, sectionName);
+ return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
+ }
+ }
+
+ for(int i=0; i<result->modCount; i++) {
+ char *sectionName = iniparser_getsecname(modfile, i);
+ if(!sectionName) {
+ return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
+ }
+
+ bool error = false;
+ result->mods[i].iniName = flib_strdupnull(sectionName);
+ result->mods[i].bitmaskIndex = inihelper_getint(modfile, &error, sectionName, "bitmaskIndex");
+ if(error) {
+ flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, sectionName);
+ return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile);
+ }
+ }
+
+ iniparser_freedict(settingfile);
+ iniparser_freedict(modfile);
+ return result;
+}
+
+void flib_cfg_meta_destroy(flib_cfg_meta *cfg) {
if(cfg) {
if(cfg->settings) {
for(int i=0; i<cfg->settingCount; i++) {
@@ -29,90 +100,18 @@
}
}
-flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) {
- if(!settingpath || !modpath) {
- return NULL;
- }
- flib_cfg_meta *result = calloc(1, sizeof(flib_cfg_meta));
- dictionary *settingfile = iniparser_load(settingpath);
- dictionary *modfile = iniparser_load(modpath);
-
- if(!result || !settingfile || !modfile) {
- goto handleError;
- }
-
- result->settingCount = iniparser_getnsec(settingfile);
- result->modCount = iniparser_getnsec(modfile);
- result->settings = calloc(result->settingCount, sizeof(flib_cfg_setting_meta));
- result->mods = calloc(result->modCount, sizeof(flib_cfg_mod_meta));
-
- if(!result->settings || !result->mods) {
- goto handleError;
- }
-
- for(int i=0; i<result->settingCount; i++) {
- char *sectionName = iniparser_getsecname(settingfile, i);
- if(!sectionName) {
- goto handleError;
- }
-
- bool error = false;
- result->settings[i].iniName = flib_strdupnull(sectionName);
- result->settings[i].title = inihelper_getstringdup(settingfile, &error, sectionName, "title");
- result->settings[i].engineCommand = inihelper_getstringdup(settingfile, &error, sectionName, "command");
- result->settings[i].image = inihelper_getstringdup(settingfile, &error, sectionName, "image");
- result->settings[i].checkOverMax = inihelper_getbool(settingfile, &error, sectionName, "checkOverMax");
- result->settings[i].times1000 = inihelper_getbool(settingfile, &error, sectionName, "times1000");
- result->settings[i].min = inihelper_getint(settingfile, &error, sectionName, "min");
- result->settings[i].max = inihelper_getint(settingfile, &error, sectionName, "max");
- result->settings[i].def = inihelper_getint(settingfile, &error, sectionName, "default");
- if(error) {
- flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, sectionName);
- goto handleError;
- }
- }
-
- for(int i=0; i<result->modCount; i++) {
- char *sectionName = iniparser_getsecname(modfile, i);
- if(!sectionName) {
- goto handleError;
- }
-
- bool error = false;
- result->mods[i].iniName = flib_strdupnull(sectionName);
- result->mods[i].bitmaskIndex = inihelper_getint(modfile, &error, sectionName, "bitmaskIndex");
- if(error) {
- flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, sectionName);
- goto handleError;
- }
- }
-
- iniparser_freedict(settingfile);
- iniparser_freedict(modfile);
- return result;
-
- handleError:
- freeCfgMeta(result);
- iniparser_freedict(settingfile);
- iniparser_freedict(modfile);
- return NULL;
-}
-
-void flib_cfg_meta_destroy(flib_cfg_meta *metainfo) {
- freeCfgMeta(metainfo);
-}
-
flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName) {
- flib_cfg *result = calloc(1, sizeof(flib_cfg));
+ flib_cfg *result = 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->schemeName = flib_strdupnull(schemeName);
- result->mods = calloc(meta->modCount, sizeof(*result->mods));
- result->settings = calloc(meta->settingCount, sizeof(*result->settings));
+ result->mods = flib_calloc(meta->modCount, sizeof(*result->mods));
+ result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings));
if(!result->mods || !result->settings || !result->schemeName) {
flib_cfg_destroy(result);
@@ -133,6 +132,7 @@
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;
}
dictionary *settingfile = iniparser_load(filename);
@@ -170,8 +170,13 @@
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) {
- dictionary *dict = dictionary_new(0);
+ if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) {
+ flib_log_e("Invalid parameter in flib_cfg_to_ini");
+ } else {
+ dictionary *dict = iniparser_load(filename);
+ if(!dict) {
+ dict = dictionary_new(0);
+ }
if(dict) {
bool error = false;
// Add the sections
--- a/project_files/frontlib/model/cfg.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/cfg.h Tue Jun 12 11:25:05 2012 +0200
@@ -44,11 +44,32 @@
bool *mods;
} flib_cfg;
+/**
+ * Read the meta-configuration from the relevant .ini files (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.
+ */
flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath);
void flib_cfg_meta_destroy(flib_cfg_meta *metainfo);
+/**
+ * Create a new configuration with default settings.
+ * Returns NULL on error.
+ */
flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName);
+
+/**
+ * Load a configuration from the ini file.
+ * Returns NULL on error.
+ */
flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename);
+
+/**
+ * Store the configuration to an ini file.
+ * Returns NULL on error.
+ */
int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config);
void flib_cfg_destroy(flib_cfg* cfg);
--- a/project_files/frontlib/model/gamesetup.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/gamesetup.h Tue Jun 12 11:25:05 2012 +0200
@@ -18,7 +18,7 @@
char *script; // optional
flib_cfg *gamescheme; // optional
flib_map *map; // optional
- flib_team *teams; // optional
+ flib_team **teams; // optional
int teamcount;
} flib_gamesetup;
--- a/project_files/frontlib/model/map.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/map.c Tue Jun 12 11:25:05 2012 +0200
@@ -11,7 +11,7 @@
if(!theme) {
flib_log_e("null parameter in flib_map_create_regular");
} else {
- flib_map *newmap = calloc(1, sizeof(flib_map));
+ flib_map *newmap = flib_calloc(1, sizeof(flib_map));
if(newmap) {
newmap->mapgen = MAPGEN_REGULAR;
newmap->templateFilter = templateFilter;
@@ -31,7 +31,7 @@
if(!theme) {
flib_log_e("null parameter in flib_map_create_maze");
} else {
- flib_map *newmap = calloc(1, sizeof(flib_map));
+ flib_map *newmap = flib_calloc(1, sizeof(flib_map));
if(newmap) {
newmap->mapgen = MAPGEN_MAZE;
newmap->mazeSize = mazeSize;
@@ -51,7 +51,7 @@
if(!name) {
flib_log_e("null parameter in flib_map_create_named");
} else {
- flib_map *newmap = calloc(1, sizeof(flib_map));
+ flib_map *newmap = flib_calloc(1, sizeof(flib_map));
if(newmap) {
newmap->mapgen = MAPGEN_NAMED;
newmap->name = flib_strdupnull(name);
@@ -70,7 +70,7 @@
if(!theme || !drawData) {
flib_log_e("null parameter in flib_map_create_named");
} else {
- flib_map *newmap = calloc(1, sizeof(flib_map));
+ flib_map *newmap = flib_calloc(1, sizeof(flib_map));
if(newmap) {
newmap->mapgen = MAPGEN_DRAWN;
newmap->drawData = flib_bufdupnull(drawData, drawDataSize);
--- a/project_files/frontlib/model/team.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/team.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,1 +1,109 @@
#include "team.h"
+
+#include "../util/inihelper.h"
+#include "../util/util.h"
+#include "../util/logging.h"
+
+static flib_team *from_ini_handleError(flib_team *result, dictionary *settingfile, char **bindingKeys) {
+ if(settingfile) {
+ iniparser_freedict(settingfile);
+ }
+ flib_team_destroy(result);
+ free(bindingKeys);
+ return NULL;
+}
+
+flib_team *flib_team_from_ini(const char *filename) {
+ flib_team *result = flib_calloc(1, sizeof(flib_team));
+ dictionary *settingfile = NULL;
+ char **bindingKeys = NULL;
+
+ if(!filename) {
+ flib_log_e("null parameter in flib_team_from_ini");
+ return from_ini_handleError(result, settingfile, bindingKeys);
+ }
+
+ if(!result) {
+ return from_ini_handleError(result, settingfile, bindingKeys);
+ }
+
+ settingfile = iniparser_load(filename);
+ if(!settingfile) {
+ flib_log_e("Error loading team file %s", filename);
+ return from_ini_handleError(result, settingfile, bindingKeys);
+ }
+
+ bool error = false;
+ result->name = inihelper_getstringdup(settingfile, &error, "team", "name");
+ result->grave = inihelper_getstringdup(settingfile, &error, "team", "grave");
+ result->fort = inihelper_getstringdup(settingfile, &error, "team", "fort");
+ result->voicepack = inihelper_getstringdup(settingfile, &error, "team", "voicepack");
+ result->flag = inihelper_getstringdup(settingfile, &error, "team", "flag");
+ result->rounds = inihelper_getint(settingfile, &error, "team", "rounds");
+ result->wins = inihelper_getint(settingfile, &error, "team", "wins");
+ result->campaignProgress = inihelper_getint(settingfile, &error, "team", "campaignprogress");
+ int difficulty = inihelper_getint(settingfile, &error, "team", "difficulty");
+
+ char sectionName[10];
+ strcpy(sectionName, "hedgehog0");
+ for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+ sectionName[8] = '0'+i;
+ result->hogs[i].name = inihelper_getstringdup(settingfile, &error, sectionName, "name");
+ result->hogs[i].hat = inihelper_getstringdup(settingfile, &error, sectionName, "hat");
+ result->hogs[i].rounds = inihelper_getint(settingfile, &error, sectionName, "rounds");
+ result->hogs[i].kills = inihelper_getint(settingfile, &error, sectionName, "kills");
+ result->hogs[i].deaths = inihelper_getint(settingfile, &error, sectionName, "deaths");
+ result->hogs[i].suicides = inihelper_getint(settingfile, &error, sectionName, "suicides");
+ result->hogs[i].difficulty = difficulty;
+ result->hogs[i].initialHealth = TEAM_DEFAULT_HEALTH;
+ }
+
+ result->bindingCount = iniparser_getsecnkeys(settingfile, "binds");
+ result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding));
+ bindingKeys = iniparser_getseckeys(settingfile, "binds");
+ if(!result->bindings || !bindingKeys) {
+ return from_ini_handleError(result, settingfile, bindingKeys);
+ }
+
+ for(int i=0; i<result->bindingCount; i++) {
+ result->bindings[i].binding = flib_strdupnull(iniparser_getstring(settingfile, bindingKeys[i], NULL));
+ // The key names all start with "binds:", so we skip that.
+ result->bindings[i].action = inihelper_urldecode(bindingKeys[i]+strlen("binds:"));
+ if(!result->bindings[i].action || !result->bindings[i].binding) {
+ error = true;
+ }
+ }
+
+ if(error) {
+ flib_log_e("Error reading team file %s", filename);
+ return from_ini_handleError(result, settingfile, bindingKeys);
+ }
+
+ iniparser_freedict(settingfile);
+ free(bindingKeys);
+ return result;
+}
+
+void flib_team_destroy(flib_team *team) {
+ if(team) {
+ for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+ free(team->hogs[i].name);
+ free(team->hogs[i].hat);
+ }
+ free(team->name);
+ free(team->grave);
+ free(team->fort);
+ free(team->voicepack);
+ free(team->flag);
+ if(team->bindings) {
+ for(int i=0; i<team->bindingCount; i++) {
+ free(team->bindings[i].action);
+ free(team->bindings[i].binding);
+ }
+ }
+ free(team->bindings);
+ free(team->hash);
+ flib_weaponset_destroy(team->weaponset);
+ free(team);
+ }
+}
--- a/project_files/frontlib/model/team.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/team.h Tue Jun 12 11:25:05 2012 +0200
@@ -12,6 +12,13 @@
#define TEAM_DEFAULT_DIFFICULTY 0
#define TEAM_DEFAULT_HEALTH 100
+// TODO default bindings?
+
+typedef struct {
+ char *action;
+ char *binding;
+} flib_binding;
+
typedef struct {
char *name;
char *hat;
@@ -19,12 +26,13 @@
// Statistics. They are irrelevant for the engine or server,
// but provided for ini reading/writing by the frontend.
int rounds;
+ int kills;
int deaths;
- int kills;
int suicides;
- // These settings are sometimes used on a per-team basis.
int difficulty;
+
+ // Transient setting used in game setup
int initialHealth;
} flib_hog;
@@ -36,16 +44,43 @@
char *voicepack;
char *flag;
- // TODO binds
+ flib_binding *bindings;
+ int bindingCount;
+
+ // Statistics. They are irrelevant for the engine or server,
+ // but provided for ini reading/writing by the frontend.
+ int rounds;
+ int wins;
+ int campaignProgress;
// Transient settings used in game setup
uint32_t color;
int hogsInGame;
bool remoteDriven;
- char *hash;
+ char *hash; // TODO calculate
- // This setting is sometimes used on a per-game basis.
flib_weaponset *weaponset;
} flib_team;
+/**
+ * Returns a new team, or NULL on error. name must not be NULL.
+ *
+ * The new team is pre-filled with default settings (see hwconsts.h)
+ */
+flib_team *flib_team_create(const char *name);
+
+/**
+ * Loads a team, returns NULL on error.
+ */
+flib_team *flib_team_from_ini(const char *filename);
+
+/**
+ * Write the team to an ini file. Attempts to retain extra ini settings
+ * that were already present. Note that not all fields of a team struct
+ * are stored in the ini, some are only used intermittently to store
+ * information about a team in the context of a game.
+ */
+int flib_team_to_ini(const char *filename, const flib_team *team);
+void flib_team_destroy(flib_team *team);
+
#endif /* TEAM_H_ */
--- a/project_files/frontlib/model/weapon.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/weapon.c Tue Jun 12 11:25:05 2012 +0200
@@ -38,7 +38,7 @@
if(!name || !loadoutStr || !crateProbStr || !crateAmmoStr || !delayStr) {
flib_log_e("null parameter in flib_weaponset_create_str");
} else {
- flib_weaponset *newSet = calloc(1, sizeof(flib_weaponset));
+ flib_weaponset *newSet = flib_calloc(1, sizeof(flib_weaponset));
char *nameCopy = flib_strdupnull(name);
if(newSet && nameCopy) {
newSet->name = nameCopy;
@@ -101,7 +101,10 @@
if(!filename || !set) {
flib_log_e("null parameter in flib_weaponset_to_ini");
} else {
- dictionary *dict = dictionary_new(0);
+ dictionary *dict = iniparser_load(filename);
+ if(!dict) {
+ dict = dictionary_new(0);
+ }
if(dict) {
bool error = false;
// Add the sections
--- a/project_files/frontlib/model/weapon.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/model/weapon.h Tue Jun 12 11:25:05 2012 +0200
@@ -7,7 +7,7 @@
* These values are all in the range 0..9
*
* For loadout, 9 means inifinite ammo.
- * For the other setting, 9 might actually be invalid, it's not possible to set more than 8 in the QtFrontend. (TODO)
+ * For the other setting, 9 is invalid.
*/
typedef struct {
char loadout[WEAPONS_COUNT+1];
@@ -25,7 +25,16 @@
* settings (see hwconsts.h)
*/
flib_weaponset *flib_weaponset_create(const char *name);
+
+/**
+ * Loads a weapon set, returns NULL on error.
+ */
flib_weaponset *flib_weaponset_from_ini(const char *filename);
+
+/**
+ * Write the weapon set to an ini file. Attempts to
+ * retain extra ini settings that were already present.
+ */
int flib_weaponset_to_ini(const char *filename, const flib_weaponset *set);
void flib_weaponset_destroy(flib_weaponset *set);
--- a/project_files/frontlib/socket.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/socket.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,5 +1,6 @@
#include "socket.h"
#include "util/logging.h"
+#include "util/util.h"
#include <stdlib.h>
#include <SDL_net.h>
#include <time.h>
@@ -23,10 +24,9 @@
return get_peer_ip(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1
}
-static flib_tcpsocket flib_socket_create(TCPsocket sdlsock) {
- flib_tcpsocket result = malloc(sizeof(_flib_tcpsocket));
+static flib_tcpsocket *flib_socket_create(TCPsocket sdlsock) {
+ flib_tcpsocket *result = flib_calloc(1, sizeof(_flib_tcpsocket));
if(!result) {
- flib_log_e("Can't allocate socket: Out of memory!");
return NULL;
}
result->sock = sdlsock;
@@ -43,10 +43,9 @@
return result;
}
-flib_acceptor flib_acceptor_create(uint16_t port) {
- flib_acceptor result = malloc(sizeof(_flib_acceptor));
+flib_acceptor *flib_acceptor_create(uint16_t port) {
+ flib_acceptor *result = flib_calloc(1, sizeof(_flib_acceptor));
if(!result) {
- flib_log_e("Can't allocate acceptor: Out of memory!");
return NULL;
}
@@ -86,7 +85,7 @@
}
}
-uint16_t flib_acceptor_listenport(flib_acceptor acceptor) {
+uint16_t flib_acceptor_listenport(flib_acceptor *acceptor) {
if(!acceptor) {
flib_log_e("Call to flib_acceptor_listenport with acceptor==null");
return 0;
@@ -94,22 +93,19 @@
return acceptor->port;
}
-void flib_acceptor_close(flib_acceptor *acceptorptr) {
- if(!acceptorptr) {
- flib_log_e("Call to flib_acceptor_close with acceptorptr==null");
- } else if(*acceptorptr) {
- SDLNet_TCP_Close((*acceptorptr)->sock);
- free(*acceptorptr);
- *acceptorptr = NULL;
+void flib_acceptor_close(flib_acceptor *acceptor) {
+ if(acceptor) {
+ SDLNet_TCP_Close(acceptor->sock);
+ free(acceptor);
}
}
-flib_tcpsocket flib_socket_accept(flib_acceptor acceptor, bool localOnly) {
+flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly) {
if(!acceptor) {
flib_log_e("Call to flib_socket_accept with acceptor==null");
return NULL;
}
- flib_tcpsocket result = NULL;
+ flib_tcpsocket *result = NULL;
TCPsocket sock = NULL;
while(!result && (sock = SDLNet_TCP_Accept(acceptor->sock))) {
if(localOnly && !connection_is_local(sock)) {
@@ -125,20 +121,16 @@
return result;
}
-void flib_socket_close(flib_tcpsocket *sockptr) {
- if(!sockptr) {
- flib_log_e("Call to flib_socket_close with sockptr==null");
- } else if(*sockptr) {
- flib_tcpsocket sock = *sockptr;
+void flib_socket_close(flib_tcpsocket *sock) {
+ if(sock) {
SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock);
SDLNet_TCP_Close(sock->sock);
SDLNet_FreeSocketSet(sock->sockset);
free(sock);
- *sockptr = NULL;
}
}
-int flib_socket_nbrecv(flib_tcpsocket sock, void *data, int maxlen) {
+int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen) {
if(!sock || (maxlen>0 && !data)) {
flib_log_e("Call to flib_socket_nbrecv with sock==null or data==null");
return -1;
@@ -155,7 +147,7 @@
}
}
-int flib_socket_send(flib_tcpsocket sock, const void *data, int len) {
+int flib_socket_send(flib_tcpsocket *sock, const void *data, int len) {
if(!sock || (len>0 && !data)) {
flib_log_e("Call to flib_socket_send with sock==null or data==null");
return -1;
--- a/project_files/frontlib/socket.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/socket.h Tue Jun 12 11:25:05 2012 +0200
@@ -16,10 +16,10 @@
#include <stdint.h>
struct _flib_tcpsocket;
-typedef struct _flib_tcpsocket *flib_tcpsocket;
+typedef struct _flib_tcpsocket flib_tcpsocket;
struct _flib_acceptor;
-typedef struct _flib_acceptor *flib_acceptor;
+typedef struct _flib_acceptor flib_acceptor;
/**
* Create a new acceptor which will listen for incoming TCP connections
@@ -28,28 +28,28 @@
*
* Can return NULL on error.
*/
-flib_acceptor flib_acceptor_create(uint16_t port);
+flib_acceptor *flib_acceptor_create(uint16_t port);
/**
* Return the port on which the acceptor is listening.
*/
-uint16_t flib_acceptor_listenport(flib_acceptor acceptor);
+uint16_t flib_acceptor_listenport(flib_acceptor *acceptor);
/**
- * Close the acceptor, free its memory and set it to NULL.
+ * Close the acceptor and free its memory.
* If the acceptor is already NULL, nothing happens.
*/
-void flib_acceptor_close(flib_acceptor *acceptorptr);
+void flib_acceptor_close(flib_acceptor *acceptor);
/**
* Try to accept a connection from an acceptor (listening socket).
* if localOnly is true, this will only accept connections which came from 127.0.0.1
* Returns NULL if nothing can be accepted.
*/
-flib_tcpsocket flib_socket_accept(flib_acceptor acceptor, bool localOnly);
+flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly);
/**
- * Close the socket, free its memory and set it to NULL.
+ * Close the socket and free its memory.
* If the socket is already NULL, nothing happens.
*/
void flib_socket_close(flib_tcpsocket *socket);
@@ -60,8 +60,8 @@
* Returns the ammount of data received, 0 if there was nothing to receive,
* or a negative number if the connection was closed or an error occurred.
*/
-int flib_socket_nbrecv(flib_tcpsocket sock, void *data, int maxlen);
+int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen);
-int flib_socket_send(flib_tcpsocket sock, const void *data, int len);
+int flib_socket_send(flib_tcpsocket *sock, const void *data, int len);
#endif /* SOCKET_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/test.c Tue Jun 12 11:25:05 2012 +0200
@@ -0,0 +1,178 @@
+#include "frontlib.h"
+#include "util/logging.h"
+#include "model/map.h"
+#include "ipc/mapconn.h"
+#include "ipc/gameconn.h"
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <assert.h>
+
+// Callback function that will be called when the map is rendered
+static void handleMapSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {
+ printf("Drawing map for %i brave little hogs...", numHedgehogs);
+
+ // Draw the map as ASCII art
+ for(int y=0; y<MAPIMAGE_HEIGHT; y++) {
+ for(int x=0; x<MAPIMAGE_WIDTH; x++) {
+ int pixelnum = x + y*MAPIMAGE_WIDTH;
+ bool pixel = bitmap[pixelnum>>3] & (1<<(7-(pixelnum&7)));
+ printf(pixel ? "#" : " ");
+ }
+ printf("\n");
+ }
+
+ // Destroy the connection object (this will end the "tick" loop below)
+ flib_mapconn **connptr = context;
+ flib_mapconn_destroy(*connptr);
+ *connptr = NULL;
+}
+
+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 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);
+}
+
+// Callback function that will be called on error
+static void handleMapFailure(void *context, const char *errormessage) {
+ flib_log_e("Map rendering failed: %s", errormessage);
+
+ // Destroy the connection object (this will end the "tick" loop below)
+ flib_mapconn **connptr = context;
+ flib_mapconn_destroy(*connptr);
+ *connptr = NULL;
+}
+
+static void startEngineMap(int port) {
+ char commandbuffer[255];
+ const char *enginePath = "C:\\Programmieren\\Hedgewars\\bin";
+ const char *configPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars";
+ snprintf(commandbuffer, 255, "start %s\\hwengine.exe %s %i landpreview", enginePath, configPath, port);
+ system(commandbuffer);
+}
+
+static void startEngineGame(int port) {
+ char commandbuffer[255];
+ const char *enginePath = "C:\\Programmieren\\Hedgewars\\bin";
+ const char *configPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars";
+ const char *dataPath = "C:\\Programmieren\\Hedgewars\\share\\hedgewars\\Data";
+ snprintf(commandbuffer, 255, "start %s\\hwengine.exe %s 1024 768 32 %i 0 0 0 10 10 %s 0 0 TWVkbzQy 0 0 en.txt", enginePath, configPath, port, dataPath);
+ flib_log_d("Starting engine with CMD: %s", commandbuffer);
+ system(commandbuffer);
+}
+
+void testMapPreview() {
+ // Create a map description and check that there was no error
+ flib_map *map = flib_map_create_maze("Jungle", MAZE_SIZE_SMALL_TUNNELS);
+ assert(map);
+
+ // Create a new connection to the engine and check that there was no error
+ flib_mapconn *mapConnection = flib_mapconn_create("This is the seed value", map);
+ assert(mapConnection);
+
+ // We don't need the map description anymore
+ flib_map_destroy(map);
+ map = NULL;
+
+ // Register the callback functions
+ flib_mapconn_onFailure(mapConnection, &handleMapFailure, &mapConnection);
+ flib_mapconn_onSuccess(mapConnection, &handleMapSuccess, &mapConnection);
+
+ // Start the engine process and tell it which port the frontlib is listening on
+ startEngineMap(flib_mapconn_getport(mapConnection));
+
+ // Usually, flib_mapconn_tick will be called in an event loop that runs several
+ // times per second. It handles I/O operations and progress, and calls
+ // callbacks when something interesting happens.
+ while(mapConnection) {
+ flib_mapconn_tick(mapConnection);
+ }
+}
+
+void testGame() {
+ 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.script = NULL;
+ setup.teamcount = 2;
+ setup.teams = calloc(2, sizeof(flib_team*));
+ setup.teams[0] = calloc(1, 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] = flib_team_from_ini("Cave Dwellers.hwt");
+ setup.teams[1]->color = 0xff0000ff;
+ setup.teams[1]->hogsInGame = 8;
+ setup.teams[1]->weaponset = flib_weaponset_create("Defaultweaps");
+
+ flib_gameconn *gameconn = flib_gameconn_create("Medo42", metaconf, &setup, false);
+ assert(gameconn);
+
+ flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn);
+ flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn);
+
+ startEngineGame(flib_gameconn_getport(gameconn));
+
+ while(gameconn) {
+ flib_gameconn_tick(gameconn);
+ }
+}
+
+void testDemo() {
+ FILE *demofile = fopen("testdemo.42.hwd", "rb");
+ assert(demofile);
+ flib_vector *vec = flib_vector_create();
+ uint8_t demobuf[512];
+ int len;
+ while((len=fread(demobuf, 1, 512, demofile))>0) {
+ flib_vector_append(vec, demobuf, len);
+ }
+ fclose(demofile);
+ flib_constbuffer constbuf = flib_vector_as_constbuffer(vec);
+ flib_gameconn *gameconn = flib_gameconn_create_playdemo(constbuf.data, constbuf.size);
+ flib_vector_destroy(vec);
+ assert(gameconn);
+ flib_gameconn_onDisconnect(gameconn, &onDisconnect, &gameconn);
+ flib_gameconn_onGameRecorded(gameconn, &onGameRecorded, &gameconn);
+ startEngineGame(flib_gameconn_getport(gameconn));
+
+ while(gameconn) {
+ flib_gameconn_tick(gameconn);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ flib_init(0);
+ flib_log_setLevel(FLIB_LOGLEVEL_ALL);
+
+ //testMapPreview();
+ testDemo();
+
+ flib_quit();
+ return 0;
+}
--- a/project_files/frontlib/util/buffer.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/buffer.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,40 +1,43 @@
#include "buffer.h"
#include "logging.h"
+#include "util.h"
#include <stdlib.h>
#include <limits.h>
#include <string.h>
+#define MIN_VECTOR_CAPACITY 16
+
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;
+flib_vector *flib_vector_create() {
+ flib_vector *result = NULL;
+ flib_vector *tmpVector = flib_calloc(1, sizeof(_flib_vector));
+ if(tmpVector) {
+ tmpVector->data = flib_malloc(MIN_VECTOR_CAPACITY);
+ if(tmpVector->data) {
+ tmpVector->size = 0;
+ tmpVector->capacity = MIN_VECTOR_CAPACITY;
+ result = tmpVector;
+ tmpVector = NULL;
+ }
}
- result->data = malloc(16);
- if(result->data == NULL) {
- free(result);
- return NULL;
- }
- result->size = 0;
- result->capacity = 16;
+ flib_vector_destroy(tmpVector);
return result;
}
void flib_vector_destroy(flib_vector *vec) {
- if(vec && *vec) {
- free((*vec)->data);
- free(*vec);
- *vec = NULL;
+ if(vec) {
+ free(vec->data);
+ free(vec);
}
}
-static void try_realloc(flib_vector vec, size_t newCapacity) {
+static void try_realloc(flib_vector *vec, size_t newCapacity) {
void *newData = realloc(vec->data, newCapacity);
if(newData) {
vec->data = newData;
@@ -42,11 +45,16 @@
}
}
-static size_t getFreeCapacity(flib_vector vec) {
+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) {
+int flib_vector_append(flib_vector *vec, const void *data, size_t len) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_append");
+ return 0;
+ }
+
if(getFreeCapacity(vec) < len) {
// Resize exponentially for constant amortized time,
// But at least by as much as we need of course,
@@ -63,7 +71,7 @@
}
// Check if we were able to resize.
- // If not, try to allocate at least what we need...
+ // If not, try to allocate at least what we need.
if(getFreeCapacity(vec) < len) {
try_realloc(vec, vec->capacity+minExtraCapacity);
@@ -74,17 +82,47 @@
}
}
- memmove(vec->data + vec->size, data, len);
+ memmove(((uint8_t*)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_buffer flib_vector_as_buffer(flib_vector *vec) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_as_buffer");
+ flib_buffer result = {NULL, 0};
+ return result;
+ } else {
+ 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;
+flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_as_constbuffer");
+ flib_constbuffer result = {NULL, 0};
+ return result;
+ } else {
+ flib_constbuffer result = {vec->data, vec->size};
+ return result;
+ }
}
+
+void *flib_vector_data(flib_vector *vec) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_data");
+ return NULL;
+ } else {
+ return vec->data;
+ }
+}
+
+size_t flib_vector_size(flib_vector *vec) {
+ if(!vec) {
+ flib_log_e("null parameter in flib_vector_size");
+ return 0;
+ } else {
+ return vec->size;
+ }
+}
--- a/project_files/frontlib/util/buffer.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/buffer.h Tue Jun 12 11:25:05 2012 +0200
@@ -24,35 +24,50 @@
} flib_constbuffer;
/**
- * Simple variable-capacity data structure (opaque type).
+ * Simple variable-capacity data structure that can be efficiently appended to.
*/
struct _flib_vector;
-typedef struct _flib_vector *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();
+flib_vector *flib_vector_create();
/**
- * Free the memory of this vector and set it to NULL.
+ * Free the memory of this vector
*/
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.
+ * The vector remains unchanged if appending fails.
*/
-int flib_vector_append(flib_vector vec, const void *data, size_t len);
+int flib_vector_append(flib_vector *vec, const void *data, size_t len);
+
+/**
+ * Return a pointer to the current data buffer of the vector. This pointer can
+ * become invalid if the vector size or capacity is changed.
+ */
+void *flib_vector_data(flib_vector *vec);
/**
- * Return a buffer or constbuffer pointing to the current contents of the vector.
+ * Return the current size of the vector.
+ */
+size_t flib_vector_size(flib_vector *vec);
+
+/**
+ * Return a buffer 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);
+flib_buffer flib_vector_as_buffer(flib_vector *vec);
+/**
+ * Return a constbuffer pointing to the current contents of the vector.
+ * These will become invalid if the vector size or capacity is changed.
+ */
+flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec);
#endif
--- a/project_files/frontlib/util/inihelper.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/inihelper.c Tue Jun 12 11:25:05 2012 +0200
@@ -22,7 +22,7 @@
return NULL;
}
- char *outbuf = malloc(insize*3+1);
+ char *outbuf = flib_malloc(insize*3+1);
if(!outbuf) {
return NULL;
}
@@ -41,11 +41,12 @@
}
}
outbuf[outpos] = 0;
- return outbuf;
+ char *shrunk = realloc(outbuf, outpos+1);
+ return shrunk ? shrunk : outbuf;
}
char *inihelper_urldecode(const char *inbuf) {
- char *outbuf = malloc(strlen(inbuf)+1);
+ char *outbuf = flib_malloc(strlen(inbuf)+1);
if(!outbuf) {
return NULL;
}
@@ -61,11 +62,13 @@
}
}
outbuf[outpos] = 0;
- return outbuf;
+ char *shrunk = realloc(outbuf, outpos+1);
+ return shrunk ? shrunk : outbuf;
}
char *inihelper_createDictKey(const char *sectionName, const char *keyName) {
if(!sectionName || !keyName) {
+ flib_log_e("null parameter in inihelper_createDictKey");
return NULL;
}
return flib_asprintf("%s:%s", sectionName, keyName);
@@ -73,6 +76,7 @@
char *inihelper_getstring(dictionary *inifile, bool *error, const char *sectionName, const char *keyName) {
if(!inifile || !sectionName || !keyName) {
+ flib_log_e("null parameter in inihelper_getstring");
*error = true;
return NULL;
}
@@ -84,7 +88,7 @@
char *result = iniparser_getstring(inifile, extendedkey, NULL);
free(extendedkey);
if(!result) {
- flib_log_i("Missing ini setting: %s/%s", sectionName, keyName);
+ flib_log_d("Missing ini setting: %s/%s", sectionName, keyName);
*error = true;
}
return result;
@@ -102,10 +106,12 @@
errno = 0;
long val = strtol(value, NULL, 10);
if(errno!=0) {
+ flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", sectionName, keyName, value);
*error = true;
return 0;
}
if(val<INT_MIN || val>INT_MAX) {
+ flib_log_w("ini setting %s/%s = \"%s\" is too large or too small.", sectionName, keyName, value);
*error = true;
return 0;
}
@@ -121,6 +127,7 @@
bool trueval = strchr("1tTyY", value[0]);
bool falseval = strchr("0fFnN", value[0]);
if(!trueval && !falseval) {
+ flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", sectionName, keyName, value);
*error = true;
return false;
} else {
@@ -132,13 +139,13 @@
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");
+ flib_log_e("null parameter in inihelper_setstr");
} else {
char *extendedkey = inihelper_createDictKey(sectionName, keyName);
if(extendedkey) {
result = iniparser_set(dict, extendedkey, value);
- free(extendedkey);
}
+ free(extendedkey);
}
return result;
}
@@ -146,7 +153,7 @@
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");
+ flib_log_e("null parameter in inihelper_setint");
} else {
char *strvalue = flib_asprintf("%i", value);
if(strvalue) {
@@ -160,7 +167,7 @@
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");
+ flib_log_e("null parameter in inihelper_setbool");
} else {
result = inihelper_setstr(dict, sectionName, keyName, value ? "true" : "false");
}
--- a/project_files/frontlib/util/inihelper.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/inihelper.h Tue Jun 12 11:25:05 2012 +0200
@@ -1,6 +1,9 @@
/**
- * Some helper functions for working with the iniparser functions - in particular,
- * for interoperability with the ini format used by the QtSettings class.
+ * Convenience interface for ini reading/writing.
+ *
+ * We currently use iniparser in the background, but using its interface directly is a bit verbose.
+ * This module is supposed to 1. make ini reading and writing a bit more convenient, and 2. hide
+ * the iniparser dependency so it can at need be easily replaced.
*/
#ifndef INIHELPER_H_
@@ -10,6 +13,9 @@
#include <stdbool.h>
+struct _flib_ini;
+typedef struct _flib_inihelper flib_ini;
+
/**
* Returned buffer must be free()d
*/
@@ -48,7 +54,20 @@
*/
bool inihelper_getbool(dictionary *inifile, bool *error, const char *sectionName, const char *keyName);
+/**
+ * Returns a nonzero value on error.
+ */
int inihelper_setstr(dictionary *dict, const char *sectionName, const char *keyName, const char *value);
+
+/**
+ * Returns a nonzero value on error.
+ */
int inihelper_setint(dictionary *dict, const char *sectionName, const char *keyName, int value);
+
+/**
+ * Set an ini setting to "true" or "false".
+ * Returns a nonzero value on error.
+ */
int inihelper_setbool(dictionary *dict, const char *sectionName, const char *keyName, bool value);
+
#endif /* INIHELPER_H_ */
--- a/project_files/frontlib/util/logging.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/logging.c Tue Jun 12 11:25:05 2012 +0200
@@ -85,3 +85,7 @@
void flib_log_setFile(FILE *file) {
flib_logfile = file;
}
+
+bool flib_log_isActive(int level) {
+ return level >= flib_log_getLevel();
+}
--- a/project_files/frontlib/util/logging.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/logging.h Tue Jun 12 11:25:05 2012 +0200
@@ -1,8 +1,9 @@
#ifndef LOGGING_H_
#define LOGGING_H_
-#include<stdint.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdbool.h>
#define FLIB_LOGLEVEL_ALL -100
#define FLIB_LOGLEVEL_DEBUG -1
@@ -11,6 +12,9 @@
#define FLIB_LOGLEVEL_ERROR 2
#define FLIB_LOGLEVEL_NONE 100
+/**
+ * Returns a pointer to a static buffer, don't free or store.
+ */
char* flib_format_ip(uint32_t numip);
void flib_log_e(const char *fmt, ...);
@@ -21,5 +25,6 @@
int flib_log_getLevel();
void flib_log_setLevel(int level);
void flib_log_setFile(FILE *logfile);
+bool flib_log_isActive(int level);
#endif /* LOGGING_H_ */
--- a/project_files/frontlib/util/util.c Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/util.c Tue Jun 12 11:25:05 2012 +0200
@@ -1,4 +1,5 @@
#include "util.h"
+#include "logging.h"
#include <stddef.h>
#include <stdarg.h>
@@ -16,16 +17,20 @@
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.
+ if(!fmt) {
+ flib_log_e("null parameter in flib_vasprintf");
+ } else {
+ int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need,
+ if(requiredSize<0) {
+ flib_log_e("Error formatting string with template \"%s\" in flib_vasprintf", fmt);
+ } else {
+ char *tmpbuf = flib_malloc(requiredSize); // allocate it
+ if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting.
result = tmpbuf;
tmpbuf = NULL;
}
+ free(tmpbuf);
}
- free(tmpbuf);
}
return result;
}
@@ -41,9 +46,25 @@
if(!buf || size==0) {
return NULL;
}
- void *result = malloc(size);
+ void *result = flib_malloc(size);
if(result) {
memcpy(result, buf, size);
}
return result;
}
+
+void *flib_malloc(size_t size) {
+ void *result = malloc(size);
+ if(!result) {
+ flib_log_e("Out of memory trying to malloc %zu bytes.", size);
+ }
+ return result;
+}
+
+void *flib_calloc(size_t count, size_t elementsize) {
+ void *result = calloc(count, elementsize);
+ if(!result) {
+ flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize);
+ }
+ return result;
+}
--- a/project_files/frontlib/util/util.h Mon Jun 11 00:06:22 2012 +0200
+++ b/project_files/frontlib/util/util.h Tue Jun 12 11:25:05 2012 +0200
@@ -13,7 +13,7 @@
char *flib_asprintf(const char *fmt, ...);
/**
- * Exactly as flib_asprintf, but accepts va_args.
+ * Exactly as flib_asprintf, but accepts a va_list.
*/
char *flib_vasprintf(const char *fmt, va_list args);
@@ -33,4 +33,16 @@
*/
void *flib_bufdupnull(const void *buf, size_t size);
+/**
+ * Simple malloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like malloc.
+ */
+void *flib_malloc(size_t size);
+
+/**
+ * Simple calloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like calloc.
+ */
+void *flib_calloc(size_t count, size_t elementsize);
+
#endif