# HG changeset patch # User Medo # Date 1340812965 -7200 # Node ID 15f722e0b96fdb0d510c9368c24e708942b541c0 # Parent 8eed495fd8daaedd9cee992f53e9eeec92d3dfae frontlib: Getting there :) Added commandline client for testing diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/cmdlineClient.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/cmdlineClient.c Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,474 @@ +#include "frontlib.h" +#include "util/logging.h" +#include "util/buffer.h" +#include "util/util.h" +#include "util/list.h" +#include "model/map.h" +#include "model/weapon.h" +#include "model/schemelist.h" +#include "ipc/mapconn.h" +#include "ipc/gameconn.h" +#include "net/netconn.h" + +#include +#include +#include +#include +#include +#include + +#define ENGINE_DIR ".\\" +#define CONFIG_DIR "..\\share\\hedgewars" +#define DATA_DIR CONFIG_DIR"\\Data" + +static flib_netconn *netconn; +static flib_gameconn *gameconn; +static flib_mapconn *mapconn; +static char nickname[128]; +static flib_cfg_meta *metacfg; +static bool netConnected = false; + +// Callback function that will be called when the map is rendered +static void handleMapGenerated(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>3] & (1<<(7-(pixelnum&7))); + printf(pixel ? "#" : " "); + } + printf("\n"); + } + + // Destroy the connection object (this will end the "tick" loop below) + flib_mapconn_destroy(mapconn); + mapconn = NULL; +} + +static void onGameDisconnect(void *context, int reason) { + flib_log_i("Connection closed. Reason: %i", reason); + flib_gameconn_destroy(gameconn); + gameconn = NULL; +} + +// 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_destroy(mapconn); + mapconn = NULL; +} + +static void startEngineMap(int port) { + char cmdbuffer[255]; + char argbuffer[255]; + snprintf(cmdbuffer, 255, "%shwengine.exe", ENGINE_DIR); + snprintf(argbuffer, 255, "%s %i landpreview", CONFIG_DIR, port); + ShellExecute(NULL, NULL, cmdbuffer, argbuffer, NULL, SW_HIDE); +} + +static void startEngineGame(int port) { + char cmdbuffer[255]; + char argbuffer[255]; + snprintf(cmdbuffer, 255, "%shwengine.exe", ENGINE_DIR); + snprintf(argbuffer, 255, "%s 1024 768 32 %i 0 0 0 10 10 %s 0 0 TWVkbzQy 0 0 en.txt", CONFIG_DIR, port, DATA_DIR); + ShellExecute(NULL, NULL, cmdbuffer, argbuffer, NULL, SW_HIDE); +} + +void testMapPreview() { + // Create a map description and check that there was no error + flib_map *map = flib_map_create_maze("This is the seed value", "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(map); + assert(mapConnection); + + // We don't need the map description anymore + flib_map_release(map); + map = NULL; + + // Register the callback functions + flib_mapconn_onFailure(mapConnection, &handleMapFailure, &mapConnection); + flib_mapconn_onSuccess(mapConnection, &handleMapGenerated, &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 handleNetDisconnect(void *context, int reason, const char *message) { + printf("Disconnected: %s", message); + flib_netconn_destroy(netconn); + netconn = NULL; +} + +void printRoomList() { + const flib_roomlist *roomlist = flib_netconn_get_roomlist(netconn); + if(roomlist) { + for(int i=0; iroomCount; i++) { + if(i>0) { + printf(", "); + } + flib_room *room = roomlist->rooms[i]; + printf("%s", room->name); + } + puts("\n"); + } else { + puts("Sorry, due to an error the room list is not available."); + } +} + +void printTeamList() { + flib_gamesetup *setup = flib_netconn_create_gameSetup(netconn); + if(setup) { + puts("The following teams are in this room:"); + for(int i=0; iteamlist->teamCount; i++) { + if(i>0) { + printf(", "); + } + printf("%s", setup->teamlist->teams[i]->name); + } + puts("\n"); + } else { + puts("Sorry, due to an error the team list is not available."); + } + flib_gamesetup_destroy(setup); +} + +void handleNetConnected(void *context) { + printf("You enter a strange house inhabited by dozens of hedgehogs. There are many rooms in here:\n"); + printRoomList(); + printf("\n\nNow, you can chat by just entering text, or join a room with /join ."); + printf(" You can also /quit or let me /describe . Once in a room, you can /add and set yourself /ready. You can also /list the available rooms (in the lobby) or the teams (in a room).\n"); + netConnected = true; +} + +void handleChat(void *context, const char *nick, const char *msg) { + printf("%s: %s\n", nick, msg); +} + +void handleEnterRoom(void *context, bool isChief) { + puts("You have entered the room."); +} + +void handleRoomJoin(void *context, const char *nick) { + if(strcmp(nick, nickname)) { + printf("%s is here.\n", nick); + } +} + +void handleRoomLeave(void *context, const char *nick, const char *partmsg) { + if(strcmp(nick, nickname)) { + printf("%s leaves.\n", nick); + } +} + +void handleReady(void *context, const char *nick, bool ready) { + if(strcmp(nick, nickname)) { + if(ready) { + printf("%s is ready to go.\n", nick); + } else { + printf("%s is not ready.\n", nick); + } + } else { + if(ready) { + printf("You are ready to go.\n"); + } else { + printf("You are not ready.\n"); + } + } +} + +void handleEmFromNet(void *context, const uint8_t *em, size_t size) { + if(gameconn) { + flib_gameconn_send_enginemsg(gameconn, (const uint8_t*)em, size); + } +} + +void handleEmFromEngine(void *context, const uint8_t *em, size_t size) { + if(netconn) { + flib_netconn_send_engineMessage(netconn, em, size); + } +} + +void handleChatFromGame(void *context, const char *message, bool teamchat) { + if(netconn) { + if(teamchat) { + flib_netconn_send_teamchat(netconn, message); + } else { + flib_netconn_send_chat(netconn, message); + } + } +} + +void handleRunGame(void *context) { + flib_gamesetup *gamesetup = flib_netconn_create_gameSetup(netconn); + if(gamesetup) { + gameconn = flib_gameconn_create(nickname, gamesetup, true); + flib_gameconn_onEngineMessage(gameconn, handleEmFromEngine, NULL); + flib_gameconn_onDisconnect(gameconn, onGameDisconnect, NULL); + flib_gameconn_onChat(gameconn, handleChatFromGame, NULL); + startEngineGame(flib_gameconn_getport(gameconn)); + } + flib_gamesetup_destroy(gamesetup); +} + +void handleNickTaken(void *context, const char *nick) { + printf("The nickname %s is already in use, please choose a different one:\n", nick); + flib_gets(nickname, sizeof(nickname)); + flib_netconn_send_nick(netconn, nickname); +} + +void handlePwRequest(void *context, const char *nick) { + printf("A password is required to log in as %s, please enter (warning: shown in cleartext):\n", nick); + char password[256]; + flib_gets(password, sizeof(password)); + flib_netconn_send_password(netconn, password); +} + +void handleMessage(void *context, int type, const char *msg) { + printf("*** %s\n", msg); +} + +void handleTeamAccepted(void *context, const char *teamname) { + printf("The team %s has been accepted.\n", teamname); +} + +void handleMapChanged(void *context, const flib_map *map, int changetype) { + if(map->mapgen != MAPGEN_NAMED && changetype != NETCONN_MAPCHANGE_THEME) { + if(mapconn) { + flib_mapconn_destroy(mapconn); + mapconn = NULL; + } + mapconn = flib_mapconn_create(map); + if(mapconn) { + flib_mapconn_onSuccess(mapconn, handleMapGenerated, NULL); + flib_mapconn_onFailure(mapconn, handleMapFailure, NULL); + startEngineMap(flib_mapconn_getport(mapconn)); + } + } +} + +void handleLeaveRoom(void *context, int reason, const char *msg) { + if(reason == NETCONN_ROOMLEAVE_ABANDONED) { + printf("The chief has abandoned the room."); + } else if(reason == NETCONN_ROOMLEAVE_KICKED) { + printf("You have been kicked from the room."); + } + if(msg) { + printf(" (%s)", msg); + } + puts(" You are back in the lobby."); +} + +void handleSchemeChanged(void *context, flib_cfg *scheme) { + printf("Game scheme: %s.\n", scheme->name); +} + +void handleWeaponsetChanged(void *context, flib_weaponset *weaponset) { + printf("Weaponset: %s.\n", weaponset->name); +} + +void handleHogcountChanged(void *context, const char *team, int count) { + printf("Team %s will send %i hogs into the fight.\n", team, count); +} + +void handleRoomAdd(void *context, const flib_room *room) { + printf("%s created a new room called %s.\n", room->owner, room->name); +} + +void handleRoomDelete(void *context, const char *roomName) { + printf("The room %s has collapsed.\n", roomName); +} + +void handleScriptChanged(void *context, const char *script) { + printf("Game Type: %s\n", script); +} + +void handleTeamAdd(void *context, flib_team *team) { + printf("%s puts the team %s to the planning board.\n", team->ownerName, team->name); +} + +void handleTeamDelete(void *context, const char *teamName) { + printf("The team %s decided not to fight this battle after all.\n", teamName); +} + +void handleTeamColorChanged(void *context, const char *name, int colorIndex) { + static const char* colorNames[] = {"red", "blue", "teal", "purple", "pink", "green", "orange", "brown", "yellow"}; + const char *colorName = "strange"; + if(colorIndex>=0 && colorIndex < 9) { + colorName = colorNames[colorIndex]; + } + printf("The team %s will wear %s uniforms today.\n", name, colorName); +} + +void tick() { + if(gameconn) { + flib_gameconn_tick(gameconn); + } + if(netconn) { + flib_netconn_tick(netconn); + } + if(mapconn) { + flib_mapconn_tick(mapconn); + } +} + +static HANDLE hStdin; + +static int init() { + hStdin = GetStdHandle(STD_INPUT_HANDLE); + if(hStdin == INVALID_HANDLE_VALUE) { + flib_log_e("Unable to get stdin handle"); + return 1; + } + if(!flib_init(0)) { + flib_log_setLevel(FLIB_LOGLEVEL_WARNING); + freopen( "CON", "w", stdout ); + freopen( "CON", "w", stderr ); + metacfg = flib_cfg_meta_from_ini("metasettings.ini"); + if(!metacfg) { + flib_quit(); + return -1; + } else { + return 0; + } + } + return -1; +} + +int main(int argc, char *argv[]) { + if(init()) { + return -1; + } + + puts("Please enter a nickname:"); + flib_gets(nickname, sizeof(nickname)); + + netconn = flib_netconn_create(nickname, metacfg, DATA_DIR"\\", "140.247.62.101", 46631); + if(!netconn) { + flib_quit(); + return -1; + } + + flib_netconn_onConnected(netconn, handleNetConnected, NULL); + flib_netconn_onDisconnected(netconn, handleNetDisconnect, NULL); + flib_netconn_onChat(netconn, handleChat, NULL); + flib_netconn_onEnterRoom(netconn, handleEnterRoom, NULL); + flib_netconn_onRunGame(netconn, handleRunGame, NULL); + flib_netconn_onEngineMessage(netconn, handleEmFromNet, NULL); + flib_netconn_onRoomJoin(netconn, handleRoomJoin, NULL); + flib_netconn_onRoomLeave(netconn, handleRoomLeave, NULL); + flib_netconn_onReadyState(netconn, handleReady, NULL); + flib_netconn_onNickTaken(netconn, handleNickTaken, NULL); + flib_netconn_onPasswordRequest(netconn, handlePwRequest, NULL); + flib_netconn_onMessage(netconn, handleMessage, NULL); + flib_netconn_onTeamAccepted(netconn, handleTeamAccepted, NULL); + flib_netconn_onMapChanged(netconn, handleMapChanged, NULL); + flib_netconn_onLeaveRoom(netconn, handleLeaveRoom, NULL); + flib_netconn_onCfgScheme(netconn, handleSchemeChanged, NULL); + flib_netconn_onWeaponsetChanged(netconn, handleWeaponsetChanged, NULL); + flib_netconn_onHogCountChanged(netconn, handleHogcountChanged, NULL); + flib_netconn_onRoomAdd(netconn, handleRoomAdd, NULL); + flib_netconn_onRoomDelete(netconn, handleRoomDelete, NULL); + flib_netconn_onScriptChanged(netconn, handleScriptChanged, NULL); + flib_netconn_onTeamAdd(netconn, handleTeamAdd, NULL); + flib_netconn_onTeamDelete(netconn, handleTeamDelete, NULL); + flib_netconn_onTeamColorChanged(netconn, handleTeamColorChanged, NULL); + + INPUT_RECORD inputRecord; + DWORD eventCount = 0; + + while(netconn || gameconn) { + tick(); + if(netconn && netConnected) { + while(PeekConsoleInput(hStdin, &inputRecord, 1, &eventCount) && eventCount>0) { + if(inputRecord.EventType != KEY_EVENT) { + ReadConsoleInput(hStdin, &inputRecord, 1, &eventCount); + } else { + printf("%s: ", nickname); + char input[256]; + if(!flib_gets(input, sizeof(input))) { + if(!memcmp("/quit", input, strlen("/quit"))) { + flib_netconn_send_quit(netconn, "Player quit."); + } else if(!memcmp("/describe ", input, strlen("/describe "))) { + const char *roomname = input+strlen("/describe "); + const flib_roomlist *roomlist = flib_netconn_get_roomlist(netconn); + flib_room *room = flib_roomlist_find(roomlist, roomname); + if(!room) { + puts("Unknown room."); + } else { + char *text = flib_asprintf( + "%s is a room created by %s, where %i players (%i teams) are %s on %s%s, using the %s scheme and %s weaponset.", + room->name, + room->owner, + room->playerCount, + room->teamCount, + room->inProgress ? "fighting" : "preparing to fight", + room->map[0]=='+' ? "" : "the map ", + !strcmp("+rnd+", room->map) ? "a random map" : + !strcmp("+maze+", room->map) ? "a random maze" : + !strcmp("+drawn+", room->map) ? "a hand-drawn map" : + room->map, + room->scheme, + room->weapons); + if(text) { + puts(text); + } + free(text); + } + } else if(!memcmp("/join ", input, strlen("/join "))) { + const char *roomname = input+strlen("/join "); + flib_netconn_send_joinRoom(netconn, roomname); + } else if(!memcmp("/ready", input, strlen("/ready"))) { + flib_netconn_send_toggleReady(netconn); + } else if(!memcmp("/loglevel ", input, strlen("/loglevel "))) { + int loglevel = atoi(input+strlen("/loglevel ")); + flib_log_setLevel(loglevel); + } else if(!memcmp("/list", input, strlen("/list"))) { + if(flib_netconn_is_in_room_context(netconn)) { + printTeamList(); + } else { + puts("From this big and expansive lobby, hallways branch off to these rooms:"); + printRoomList(); + } + } else if(!memcmp("/addteam ", input, strlen("/addteam "))) { + const char *teamname = input+strlen("/addteam "); + if(!flib_contains_dir_separator(teamname)) { + char *teamfilename = flib_asprintf("%s.hwt", teamname); + if(teamfilename) { + flib_team *team = flib_team_from_ini(teamfilename); + if(team) { + flib_netconn_send_addTeam(netconn, team); + } else { + printf("Teamfile %s not found.\n", teamfilename); + } + flib_team_release(team); + } + free(teamfilename); + } + } else if(strlen(input)>0) { + flib_netconn_send_chat(netconn, input); + } + } + } + } + } + fflush(stdout); + Sleep(10); + } + + + flib_cfg_meta_release(metacfg); + return 0; +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/hwconsts.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/hwconsts.c Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,4 @@ +#include "hwconsts.h" + +const uint32_t flib_teamcolor_defaults[] = HW_TEAMCOLOR_ARRAY; +const size_t flib_teamcolor_defaults_len = sizeof(flib_teamcolor_defaults)/sizeof(uint32_t)-1; diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/hwconsts.h --- a/project_files/frontlib/hwconsts.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/hwconsts.h Wed Jun 27 18:02:45 2012 +0200 @@ -1,3 +1,22 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * Copyright (c) 2012 Simeon Maxein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + /** * This file contains important constants which might need to be changed to adapt to * changes in the engine or protocols. @@ -6,14 +25,34 @@ #ifndef HWCONSTS_H_ #define HWCONSTS_H_ +#include +#include + #define HEDGEHOGS_PER_TEAM 8 #define NETGAME_DEFAULT_PORT 46631 -#define PROTOCOL_VERSION 41 +#define PROTOCOL_VERSION 42 #define MIN_SERVER_VERSION 1 -#define GAMEMOD_PERHOGAMMO_MASKBIT 22 -#define GAMEMOD_SHAREDAMMO_MASKBIT 16 +// Used for sending scripts to the engine +#define MULTIPLAYER_SCRIPT_PATH "Scripts/Multiplayer/" #define WEAPONS_COUNT 55 +/* A merge of mikade/bugq colours w/ a bit of channel feedback */ +#define HW_TEAMCOLOR_ARRAY { UINT32_C(0xffff0204), /* red */ \ + UINT32_C(0xff4980c1), /* blue */ \ + UINT32_C(0xff1de6ba), /* teal */ \ + UINT32_C(0xffb541ef), /* purple */ \ + UINT32_C(0xffe55bb0), /* pink */ \ + UINT32_C(0xff20bf00), /* green */ \ + UINT32_C(0xfffe8b0e), /* orange */ \ + UINT32_C(0xff5f3605), /* brown */ \ + UINT32_C(0xffffff01), /* yellow */ \ + /* add new colors here */ \ + 0 } /* Keep this 0 at the end or the length will be calculated wrong */ + +// TODO allow setting alternative color lists? +extern const size_t flib_teamcolor_defaults_len; +extern const uint32_t flib_teamcolor_defaults[]; + #endif diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/ipc/gameconn.c --- a/project_files/frontlib/ipc/gameconn.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.c Wed Jun 27 18:02:45 2012 +0200 @@ -38,7 +38,7 @@ void (*onGameRecordedCb)(void *context, const uint8_t *record, int size, bool isSavegame); void *onGameRecordedCtx; - void (*onEngineMessageCb)(void *context, const uint8_t *em, int size); + void (*onEngineMessageCb)(void *context, const uint8_t *em, size_t size); void *onEngineMessageCtx; bool running; @@ -52,7 +52,7 @@ } 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_onEngineMessage(void *context, const uint8_t *em, int size) {} +static void defaultCallback_onEngineMessage(void *context, const uint8_t *em, size_t size) {} static void clearCallbacks(flib_gameconn *conn) { conn->onConnectCb = &defaultCallback_onConnect; @@ -65,23 +65,25 @@ static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) { flib_gameconn *result = NULL; - flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn)); - if(tempConn) { - tempConn->ipcBase = flib_ipcbase_create(); - tempConn->configBuffer = flib_vector_create(); - tempConn->playerName = flib_strdupnull(playerName); - if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) { - if(record) { - tempConn->demoBuffer = flib_vector_create(); + if(!log_badparams_if(!playerName)) { + flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn)); + if(tempConn) { + tempConn->ipcBase = flib_ipcbase_create(); + tempConn->configBuffer = flib_vector_create(); + tempConn->playerName = flib_strdupnull(playerName); + if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) { + if(record) { + tempConn->demoBuffer = flib_vector_create(); + } + tempConn->state = AWAIT_CONNECTION; + tempConn->netgame = netGame; + clearCallbacks(tempConn); + result = tempConn; + tempConn = NULL; } - tempConn->state = AWAIT_CONNECTION; - tempConn->netgame = netGame; - clearCallbacks(tempConn); - result = tempConn; - tempConn = NULL; } + flib_gameconn_destroy(tempConn); } - flib_gameconn_destroy(tempConn); return result; } @@ -89,7 +91,9 @@ flib_gameconn *result = NULL; flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame); if(tempConn) { - if(!flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) { + if(flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) { + flib_log_e("Error generating full game configuration for the engine."); + } else { result = tempConn; tempConn = NULL; } @@ -102,7 +106,7 @@ 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) { + if(!flib_vector_append(tempConn->configBuffer, demo, size)) { result = tempConn; tempConn = NULL; } @@ -115,7 +119,7 @@ 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) { + if(!flib_vector_append(tempConn->configBuffer, save, size)) { result = tempConn; tempConn = NULL; } @@ -161,17 +165,15 @@ } int flib_gameconn_getport(flib_gameconn *conn) { - if(!conn) { - flib_log_e("null parameter in flib_gameconn_getport"); - return 0; - } else { + if(!log_badparams_if(!conn)) { return flib_ipcbase_port(conn->ipcBase); } + return 0; } 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) { + if(flib_vector_append(conn->demoBuffer, data, len)) { flib_log_e("Error recording demo: Out of memory."); flib_vector_destroy(conn->demoBuffer); conn->demoBuffer = NULL; @@ -213,11 +215,10 @@ } } -int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len) { +int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t len) { int result = -1; - if(!conn || (!data && len>0)) { - flib_log_e("null parameter in flib_gameconn_send_enginemsg"); - } else if(!flib_ipcbase_send_raw(conn->ipcBase, data, len)) { + if(!log_badparams_if(!conn || (!data && len>0)) + && !flib_ipcbase_send_raw(conn->ipcBase, data, len)) { demo_append(conn, data, len); result = 0; } @@ -301,7 +302,7 @@ } } -void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context) { +void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, size_t size), void* context) { if(!conn) { flib_log_e("null parameter in flib_gameconn_onEngineMessage"); } else { diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/ipc/gameconn.h --- a/project_files/frontlib/ipc/gameconn.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/ipc/gameconn.h Wed Jun 27 18:02:45 2012 +0200 @@ -34,7 +34,7 @@ */ void flib_gameconn_tick(flib_gameconn *conn); -int flib_gameconn_send_enginemsg(flib_gameconn *conn, uint8_t *data, int len); +int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t 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); @@ -72,9 +72,9 @@ /** * ...needs to be passed on to the server in a net game - * handleEngineMessage(void *context, const uint8_t *em, int size) + * handleEngineMessage(void *context, const uint8_t *em, size_t size) */ -void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, int size), void* context); +void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, size_t size), void* context); // TODO efinish diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/ipc/ipcprotocol.c --- a/project_files/frontlib/ipc/ipcprotocol.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/ipc/ipcprotocol.c Wed Jun 27 18:02:45 2012 +0200 @@ -10,9 +10,7 @@ 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"); - } else { + if(!log_badparams_if(!vec || !fmt)) { // 1 byte size prefix, 255 bytes max message length, 1 0-byte for vsnprintf char msgbuffer[257]; @@ -22,18 +20,13 @@ int msgSize = vsnprintf(msgbuffer+1, 256, fmt, argp); va_end(argp); - if(msgSize > 255) { - flib_log_e("Message too long (%u bytes) in flib_ipc_appendmessage", (unsigned)msgSize); - } else if(msgSize<0) { - flib_log_e("printf error in flib_ipc_appendmessage"); - } else { + if(!log_e_if(msgSize > 255, "Message too long (%u bytes)", (unsigned)msgSize) + && !log_e_if(msgSize < 0, "printf error")) { // Add the length prefix ((uint8_t*)msgbuffer)[0] = msgSize; // Append it to the vector - if(flib_vector_append(vec, msgbuffer, msgSize+1) == msgSize+1) { - result = 0; - } + result = flib_vector_append(vec, msgbuffer, msgSize+1); } } return result; @@ -42,26 +35,16 @@ int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !map) { - flib_log_e("null parameter in flib_ipc_append_mapconf"); - } else if(tempvector) { + if(!log_badparams_if(!vec || !map)) { bool error = false; if(map->mapgen == MAPGEN_NAMED) { - if(map->name) { - error |= flib_ipc_append_message(tempvector, "emap %s", map->name); - } else { - flib_log_e("Missing map name"); - error = true; - } + error |= log_e_if(!map->name, "Missing map name") + || flib_ipc_append_message(tempvector, "emap %s", map->name); } - if(map->theme && !mappreview) { - if(map->theme) { - error |= flib_ipc_append_message(tempvector, "etheme %s", map->theme); - } else { - flib_log_e("Missing map theme"); - error = true; - } + if(!mappreview) { + error |= log_e_if(!map->theme, "Missing map theme") + || flib_ipc_append_message(tempvector, "etheme %s", map->theme); } error |= flib_ipc_append_seed(tempvector, map->seed); error |= flib_ipc_append_message(tempvector, "e$template_filter %i", map->templateFilter); @@ -81,16 +64,16 @@ int bytesRemaining = map->drawDataSize-offset; int fragmentsize = bytesRemaining < 200 ? bytesRemaining : 200; uint8_t messagesize = edrawlen + fragmentsize; - error |= (flib_vector_append(tempvector, &messagesize, 1) != 1); - error |= (flib_vector_append(tempvector, edraw, edrawlen) != edrawlen); - error |= (flib_vector_append(tempvector, map->drawData+offset, fragmentsize) != fragmentsize); + error |= flib_vector_append(tempvector, &messagesize, 1); + error |= flib_vector_append(tempvector, edraw, edrawlen); + error |= flib_vector_append(tempvector, map->drawData+offset, fragmentsize); } } - if(!error) { + if(!log_e_if(error, "Error generating map config")) { // 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) { + if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { result = 0; } } @@ -100,53 +83,69 @@ } 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; - } else { + if(!log_badparams_if(!vec || !seed)) { return flib_ipc_append_message(vec, "eseed %s", seed); } + return -1; } int flib_ipc_append_script(flib_vector *vec, const char *script) { - if(!vec || !script) { - flib_log_e("null parameter in flib_ipc_append_script"); - return -1; - } else { - return flib_ipc_append_message(vec, "escript %s", script); + int result = -1; + char *copy = flib_strdupnull(script); + if(!log_badparams_if(!vec) && copy) { + if(!strcmp("Normal", copy)) { + // "Normal" means no gametype script + result = 0; + } else { + size_t len = strlen(copy); + for(size_t i=0; imeta->modCount; i++) { + if(scheme->mods[i]) { + int bitmaskIndex = scheme->meta->mods[i].bitmaskIndex; + result |= (UINT32_C(1) << bitmaskIndex); + } + } + return result; } int flib_ipc_append_gamescheme(flib_vector *vec, const flib_cfg *scheme) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !scheme) { - flib_log_e("null parameter in flib_ipc_append_gamescheme"); - } else if(tempvector) { + if(!log_badparams_if(!vec || !scheme) && tempvector) { const flib_cfg_meta *meta = scheme->meta; bool error = false; - uint32_t gamemods = 0; - for(int i=0; imodCount; i++) { - if(scheme->mods[i]) { - gamemods |= (1<mods[i].bitmaskIndex); - } - } - error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, gamemods); + error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, buildModFlags(scheme)); for(int i=0; isettingCount; i++) { - int value = scheme->settings[i]; - if(meta->settings[i].maxMeansInfinity) { - value = value>=meta->settings[i].max ? 9999 : value; + if(meta->settings[i].engineCommand) { + int value = scheme->settings[i]; + if(meta->settings[i].maxMeansInfinity) { + value = value>=meta->settings[i].max ? 9999 : value; + } + if(meta->settings[i].times1000) { + value *= 1000; + } + error |= flib_ipc_append_message(tempvector, "%s %i", meta->settings[i].engineCommand, 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) { + if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { result = 0; } } @@ -165,19 +164,23 @@ int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !team) { - flib_log_e("invalid parameter in flib_ipc_append_addteam"); - } else if(tempvector) { + if(!log_badparams_if(!vec || !team) && tempvector) { bool error = false; if(!perHogAmmo && !noAmmoStore) { - error |= appendWeaponSet(tempvector, team->hogs[0].weaponset); - error |= flib_ipc_append_message(tempvector, "eammstore"); + error = error + || appendWeaponSet(tempvector, team->hogs[0].weaponset) + || flib_ipc_append_message(tempvector, "eammstore"); } // TODO char *hash = team->ownerName ? team->ownerName : "00000000000000000000000000000000"; - error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", hash, team->color, team->name); + if(team->colorIndex<0 || team->colorIndex>=flib_teamcolor_defaults_len) { + flib_log_e("Color index out of bounds for team %s: %i", team->name, team->colorIndex); + error = true; + } else { + error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", hash, flib_teamcolor_defaults[team->colorIndex], team->name); + } if(team->remoteDriven) { error |= flib_ipc_append_message(tempvector, "erdriven"); @@ -203,7 +206,7 @@ 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) { + if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { result = 0; } } @@ -212,22 +215,20 @@ return result; } -static bool getGameMod(const flib_cfg *conf, int maskbit) { +static bool getGameMod(const flib_cfg *conf, const char *name) { for(int i=0; imeta->modCount; i++) { - if(conf->meta->mods[i].bitmaskIndex == maskbit) { + if(!strcmp(conf->meta->mods[i].name, name)) { return conf->mods[i]; } } - flib_log_e("Unable to find game mod with mask bit %i", maskbit); + flib_log_e("Unable to find game mod %s", name); return false; } int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) { int result = -1; flib_vector *tempvector = flib_vector_create(); - if(!vec || !setup) { - flib_log_e("null parameter in flib_ipc_append_fullconfig"); - } else if(tempvector) { + if(!log_badparams_if(!vec || !setup) && tempvector) { bool error = false; bool perHogAmmo = false; bool sharedAmmo = false; @@ -237,40 +238,37 @@ error |= flib_ipc_append_mapconf(tempvector, setup->map, false); } if(setup->script) { - error |= flib_ipc_append_message(tempvector, "escript %s", setup->script); + error |= flib_ipc_append_script(tempvector, setup->script); } if(setup->gamescheme) { error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme); - sharedAmmo = getGameMod(setup->gamescheme, GAMEMOD_SHAREDAMMO_MASKBIT); + sharedAmmo = getGameMod(setup->gamescheme, "sharedammo"); // Shared ammo has priority over per-hog ammo - perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, GAMEMOD_PERHOGAMMO_MASKBIT); + perHogAmmo = !sharedAmmo && getGameMod(setup->gamescheme, "perhogammo"); } - if(setup->teams && setup->teamCount>0) { - uint32_t *clanColors = flib_calloc(setup->teamCount, sizeof(uint32_t)); + if(setup->teamlist->teams && setup->teamlist->teamCount>0) { + int *clanColors = flib_calloc(setup->teamlist->teamCount, sizeof(int)); if(!clanColors) { error = true; } else { int clanCount = 0; - for(int i=0; iteamCount; i++) { - flib_team *team = setup->teams[i]; - bool newClan = false; - + for(int i=0; !error && iteamlist->teamCount; i++) { + flib_team *team = setup->teamlist->teams[i]; // Find the clan index of this team (clans are identified by color). - // The upper 8 bits (alpha) are ignored in the engine as well. - uint32_t color = team->color&UINT32_C(0x00ffffff); + bool newClan = false; int clan = 0; - while(clancolorIndex) { clan++; } if(clan==clanCount) { newClan = true; clanCount++; - clanColors[clan] = color; + clanColors[clan] = team->colorIndex; } // If shared ammo is active, only add an ammo store for the first team in each clan. bool noAmmoStore = sharedAmmo&&!newClan; - error |= flib_ipc_append_addteam(tempvector, setup->teams[i], perHogAmmo, noAmmoStore); + error |= flib_ipc_append_addteam(tempvector, setup->teamlist->teams[i], perHogAmmo, noAmmoStore); } } free(clanColors); @@ -280,7 +278,7 @@ 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) { + if(!flib_vector_append(vec, constbuf.data, constbuf.size)) { result = 0; } } diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/ipc/mapconn.c --- a/project_files/frontlib/ipc/mapconn.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/ipc/mapconn.c Wed Jun 27 18:02:45 2012 +0200 @@ -39,7 +39,7 @@ conn->onFailureCb = &noop_handleFailure; } -static flib_vector *createConfigBuffer(flib_map *mapdesc) { +static flib_vector *createConfigBuffer(const flib_map *mapdesc) { flib_vector *result = NULL; flib_vector *tempbuffer = flib_vector_create(); if(tempbuffer) { @@ -55,7 +55,7 @@ return result; } -flib_mapconn *flib_mapconn_create(flib_map *mapdesc) { +flib_mapconn *flib_mapconn_create(const flib_map *mapdesc) { flib_mapconn *result = NULL; flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn)); if(tempConn) { diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/ipc/mapconn.h --- a/project_files/frontlib/ipc/mapconn.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/ipc/mapconn.h Wed Jun 27 18:02:45 2012 +0200 @@ -17,10 +17,14 @@ * engine process. Once this connection is established, the required information * will be sent to the engine, and the reply is read. * + * The map must be a regular, maze or drawn map - for a preview of a named map, + * use the preview images in the map's directory, and for the hog count read the + * map information (flib_mapcfg_read). + * * No NULL parameters allowed, returns NULL on failure. * Use flib_mapconn_destroy to free the returned object. */ -flib_mapconn *flib_mapconn_create(flib_map *mapdesc); +flib_mapconn *flib_mapconn_create(const flib_map *mapdesc); /** * Destroy the mapconn object. Passing NULL is allowed and does nothing. diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/cfg.c --- a/project_files/frontlib/model/cfg.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/cfg.c Wed Jun 27 18:02:45 2012 +0200 @@ -170,7 +170,7 @@ return result; } -flib_cfg *flib_cfg_copy(flib_cfg *cfg) { +flib_cfg *flib_cfg_copy(const flib_cfg *cfg) { flib_cfg *result = NULL; if(cfg) { result = flib_cfg_create(cfg->meta, cfg->name); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/cfg.h --- a/project_files/frontlib/model/cfg.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/cfg.h Wed Jun 27 18:02:45 2012 +0200 @@ -73,7 +73,7 @@ /** * Create a copy of the scheme. Returns NULL on error or if NULL was passed. */ -flib_cfg *flib_cfg_copy(flib_cfg *cfg); +flib_cfg *flib_cfg_copy(const flib_cfg *cfg); /** * Increase the reference count of the object. Call this if you store a pointer to it somewhere. diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/gamesetup.c --- a/project_files/frontlib/model/gamesetup.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/gamesetup.c Wed Jun 27 18:02:45 2012 +0200 @@ -1,2 +1,13 @@ #include "gamesetup.h" +#include + +void flib_gamesetup_destroy(flib_gamesetup *gamesetup) { + if(gamesetup) { + free(gamesetup->script); + flib_cfg_release(gamesetup->gamescheme); + flib_map_release(gamesetup->map); + flib_teamlist_destroy(gamesetup->teamlist); + free(gamesetup); + } +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/gamesetup.h --- a/project_files/frontlib/model/gamesetup.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/gamesetup.h Wed Jun 27 18:02:45 2012 +0200 @@ -9,14 +9,15 @@ #include "cfg.h" #include "weapon.h" #include "map.h" -#include "team.h" +#include "teamlist.h" typedef struct { char *script; flib_cfg *gamescheme; flib_map *map; - int teamCount; - flib_team **teams; + flib_teamlist *teamlist; } flib_gamesetup; +void flib_gamesetup_destroy(flib_gamesetup *gamesetup); + #endif diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/map.h --- a/project_files/frontlib/model/map.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/map.h Wed Jun 27 18:02:45 2012 +0200 @@ -1,12 +1,3 @@ -/** - * Data structure for defining a map. This contains the whole recipe to - * exactly recreate a particular map. For named maps, you also need the - * corresponding files. - * - * The required fields depend on the map generator, see the comments - * at the struct for details. - */ - #ifndef MODEL_MAP_H_ #define MODEL_MAP_H_ @@ -32,12 +23,20 @@ #define MAZE_SIZE_MEDIUM_ISLANDS 4 #define MAZE_SIZE_LARGE_ISLANDS 5 +/** + * Data structure for defining a map. This contains the whole recipe to + * exactly recreate a particular map. For named maps, you also need the + * corresponding files. + * + * The required fields depend on the map generator, see the comments + * at the struct for details. + */ typedef struct { int _referenceCount; int mapgen; // Always one of the MAPGEN_ constants char *name; // The name of the map for MAPGEN_NAMED, otherwise one of "+rnd+", "+maze+" or "+drawn+". char *seed; // Used for all maps - char *theme; // Used for all except MAPGEN_NAMED + char *theme; // Used for all maps uint8_t *drawData; // Used for MAPGEN_DRAWN int drawDataSize; // Used for MAPGEN_DRAWN int templateFilter; // Used for MAPGEN_REGULAR diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/mapcfg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/mapcfg.c Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,44 @@ +#include "mapcfg.h" + +#include "../util/util.h" +#include "../util/logging.h" + +#include +#include +#include +#include + +void removeNewline(char *str) { + for(;*str;str++) { + if(*str=='\n' || *str=='\r') { + *str = 0; + return; + } + } +} + +int flib_mapcfg_read(const char *dataDirPath, const char *mapname, flib_mapcfg *out) { + int result = -1; + if(!log_badparams_if(!dataDirPath || !mapname || !out) + && !log_e_if(flib_contains_dir_separator(mapname), "Illegal character in mapname %s", mapname)) { + char *path = flib_asprintf("%sMaps/%s/map.cfg", dataDirPath, mapname); + if(path) { + FILE *file = fopen(path, "rb"); + if(!log_e_if(!file, "Unable to open map config file %s", path)) { + if(!log_e_if(!fgets(out->theme, sizeof(out->theme), file), "Error reading theme from %s", path)) { + removeNewline(out->theme); + char buf[64]; + if(!log_e_if(!fgets(buf, sizeof(buf), file), "Error reading hoglimit from %s", path)) { + removeNewline(buf); + errno = 0; + out->hogLimit = strtol(buf, NULL, 10); + result = !log_e_if(errno, "Invalid hoglimit in %s: %i", path, buf); + } + } + fclose(file); + } + } + free(path); + } + return result; +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/mapcfg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/mapcfg.h Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,19 @@ +/* + * Data structure and functions for accessing the map.cfg of named maps. + */ + +#ifndef MAPCFG_H_ +#define MAPCFG_H_ + +typedef struct { + char theme[256]; + int hogLimit; +} flib_mapcfg; + +/** + * Read the map configuration for the map with this name. + * The dataDirPath must end in a path separator. + */ +int flib_mapcfg_read(const char *dataDirPath, const char *mapname, flib_mapcfg *out); + +#endif /* MAPCFG_H_ */ diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/roomlist.c --- a/project_files/frontlib/model/roomlist.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/roomlist.c Wed Jun 27 18:02:45 2012 +0200 @@ -11,7 +11,7 @@ return flib_calloc(1, sizeof(flib_roomlist)); } -static void flib_roomlist_room_destroy(flib_roomlist_room *room) { +static void flib_roomlist_room_destroy(flib_room *room) { if(room) { free(room->map); free(room->name); @@ -27,13 +27,14 @@ for(int i=0; iroomCount; i++) { flib_roomlist_room_destroy(list->rooms[i]); } + free(list->rooms); free(list); } } -static flib_roomlist_room *fillRoomFromParams(char **params) { - flib_roomlist_room *result = NULL; - flib_roomlist_room *tmpRoom = flib_calloc(1, sizeof(flib_roomlist_room)); +static flib_room *fillRoomFromParams(char **params) { + flib_room *result = NULL; + flib_room *tmpRoom = flib_calloc(1, sizeof(flib_room)); if(tmpRoom) { tmpRoom->inProgress = !strcmp(params[0], "True"); tmpRoom->name = flib_strdupnull(params[1]); @@ -52,16 +53,26 @@ return result; } +GENERATE_STATIC_LIST_INSERT(insertRoom, flib_room*) +GENERATE_STATIC_LIST_DELETE(deleteRoom, flib_room*) + +static int findRoom(const flib_roomlist *list, const char *name) { + for(int i=0; iroomCount; i++) { + if(!strcmp(name, list->rooms[i]->name)) { + return i; + } + } + return -1; +} + int flib_roomlist_add(flib_roomlist *list, char **params) { int result = -1; if(!list || !params) { flib_log_e("null parameter in flib_roomlist_add"); } else { - flib_roomlist_room *tmpRoom = fillRoomFromParams(params); + flib_room *tmpRoom = fillRoomFromParams(params); if(tmpRoom) { - flib_roomlist_room **rooms = flib_list_insert(list->rooms, &list->roomCount, sizeof(*list->rooms), &tmpRoom, 0); - if(rooms) { - list->rooms = rooms; + if(!insertRoom(&list->rooms, &list->roomCount, tmpRoom, 0)) { tmpRoom = NULL; result = 0; } @@ -71,13 +82,23 @@ return result; } -static int findRoom(flib_roomlist *list, const char *name) { - for(int i=0; iroomCount; i++) { - if(!strcmp(name, list->rooms[i]->name)) { - return i; +int flib_roomlist_delete(flib_roomlist *list, const char *name) { + int result = -1; + if(!list || !name) { + flib_log_e("null parameter in flib_roomlist_delete"); + } else { + int roomid = findRoom(list, name); + if(roomid<0) { + flib_log_w("Attempt to delete unknown room %s", name); + } else { + flib_room *room = list->rooms[roomid]; + if(!deleteRoom(&list->rooms, &list->roomCount, roomid)) { + flib_roomlist_room_destroy(room); + result = 0; + } } } - return -1; + return result; } int flib_roomlist_update(flib_roomlist *list, const char *name, char **params) { @@ -85,7 +106,7 @@ if(!list || !name || !params) { flib_log_e("null parameter in flib_roomlist_update"); } else { - flib_roomlist_room *tmpRoom = fillRoomFromParams(params); + flib_room *tmpRoom = fillRoomFromParams(params); int roomid = findRoom(list, name); if(tmpRoom && roomid>=0) { flib_roomlist_room_destroy(list->rooms[roomid]); @@ -98,8 +119,8 @@ return result; } -flib_roomlist_room *flib_roomlist_find(flib_roomlist *list, const char *name) { - flib_roomlist_room *result = NULL; +flib_room *flib_roomlist_find(const flib_roomlist *list, const char *name) { + flib_room *result = NULL; if(!list || !name) { flib_log_e("null parameter in flib_roomlist_find"); } else { @@ -123,24 +144,3 @@ list->roomCount = 0; } } - -int flib_roomlist_delete(flib_roomlist *list, const char *name) { - int result = -1; - if(!list || !name) { - flib_log_e("null parameter in flib_roomlist_delete"); - } else { - int roomid = findRoom(list, name); - if(roomid<0) { - flib_log_w("Attempt to delete unknown room %s", name); - } else { - flib_roomlist_room *room = list->rooms[roomid]; - flib_roomlist_room **rooms = flib_list_delete(list->rooms, &list->roomCount, sizeof(*list->rooms), roomid); - if(rooms || list->roomCount==0) { - list->rooms = rooms; - flib_roomlist_room_destroy(room); - result = 0; - } - } - } - return result; -} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/roomlist.h --- a/project_files/frontlib/model/roomlist.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/roomlist.h Wed Jun 27 18:02:45 2012 +0200 @@ -16,11 +16,11 @@ char *map; // This is either a map name, or one of +rnd+, +maze+ or +drawn+. char *scheme; char *weapons; -} flib_roomlist_room; +} flib_room; typedef struct { int roomCount; - flib_roomlist_room **rooms; + flib_room **rooms; } flib_roomlist; flib_roomlist *flib_roomlist_create(); @@ -45,7 +45,7 @@ /** * Returns the room with the name [name] from the list if it exists, NULL otherwise */ -flib_roomlist_room *flib_roomlist_find(flib_roomlist *list, const char *name); +flib_room *flib_roomlist_find(const flib_roomlist *list, const char *name); /** * Removes all rooms from the list diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/schemelist.c --- a/project_files/frontlib/model/schemelist.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/schemelist.c Wed Jun 27 18:02:45 2012 +0200 @@ -16,6 +16,7 @@ for(int i=0; ischemeCount; i++) { flib_cfg_release(list->schemes[i]); } + free(list->schemes); free(list); } } @@ -192,29 +193,28 @@ return NULL; } +GENERATE_STATIC_LIST_INSERT(insertScheme, flib_cfg*) +GENERATE_STATIC_LIST_DELETE(deleteScheme, flib_cfg*) + int flib_schemelist_insert(flib_schemelist *list, flib_cfg *cfg, int pos) { - flib_cfg **changedList = flib_list_insert(list->schemes, &list->schemeCount, sizeof(*list->schemes), &cfg, pos); - if(changedList) { - list->schemes = changedList; + if(!list) { + flib_log_e("Invalid parameter in flib_schemelist_insert"); + } else if(!insertScheme(&list->schemes, &list->schemeCount, cfg, pos)) { flib_cfg_retain(cfg); return 0; - } else { - return -1; } + return -1; } int flib_schemelist_delete(flib_schemelist *list, int pos) { - int result = -1; - if(!list || pos<0 || pos>=list->schemeCount) { + if(!list) { flib_log_e("Invalid parameter in flib_schemelist_delete"); } else { flib_cfg *elem = list->schemes[pos]; - flib_cfg **changedList = flib_list_delete(list->schemes, &list->schemeCount, sizeof(*list->schemes), pos); - if(changedList || list->schemeCount==0) { - list->schemes = changedList; + if(!deleteScheme(&list->schemes, &list->schemeCount, pos)) { flib_cfg_release(elem); - result = 0; + return 0; } } - return result; + return -1; } diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/team.c --- a/project_files/frontlib/model/team.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/team.c Wed Jun 27 18:02:45 2012 +0200 @@ -231,6 +231,14 @@ } } +void flib_team_set_health(flib_team *team, int health) { + if(team) { + for(int i=0; ihogs[i].initialHealth = health; + } + } +} + char *strdupWithError(const char *in, bool *error) { char *out = flib_strdupnull(in); if(in && !out) { @@ -239,7 +247,7 @@ return out; } -flib_team *flib_team_copy(flib_team *team) { +flib_team *flib_team_copy(const flib_team *team) { flib_team *result = NULL; if(team) { flib_team *tmpTeam = flib_team_retain(flib_calloc(1, sizeof(flib_team))); @@ -282,7 +290,7 @@ tmpTeam->wins = team->wins; tmpTeam->campaignProgress = team->campaignProgress; - tmpTeam->color = team->color; + tmpTeam->colorIndex = team->colorIndex; tmpTeam->hogsInGame = team->hogsInGame; tmpTeam->remoteDriven = team->remoteDriven; diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/team.h --- a/project_files/frontlib/model/team.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/team.h Wed Jun 27 18:02:45 2012 +0200 @@ -62,7 +62,7 @@ int campaignProgress; // Transient settings used in game setup - uint32_t color; + int colorIndex; // Index into a color table int hogsInGame; bool remoteDriven; char *ownerName; @@ -98,6 +98,11 @@ void flib_team_set_weaponset(flib_team *team, flib_weaponset *set); /** + * Set the same initial health for every hog. + */ +void flib_team_set_health(flib_team *team, int health); + +/** * Increase the reference count of the object. Call this if you store a pointer to it somewhere. * Returns the parameter. */ @@ -113,6 +118,6 @@ * The referenced weaponsets are not copied, so the new * team references the same weaponsets. */ -flib_team *flib_team_copy(flib_team *team); +flib_team *flib_team_copy(const flib_team *team); #endif /* TEAM_H_ */ diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/teamlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/teamlist.c Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,87 @@ +#include "teamlist.h" + +#include "../util/util.h" +#include "../util/list.h" +#include "../util/logging.h" + +#include +#include + +flib_teamlist *flib_teamlist_create() { + return flib_calloc(1, sizeof(flib_teamlist)); +} + +void flib_teamlist_destroy(flib_teamlist *list) { + if(list) { + for(int i=0; iteamCount; i++) { + flib_team_release(list->teams[i]); + } + free(list->teams); + free(list); + } +} + +GENERATE_STATIC_LIST_INSERT(insertTeam, flib_team*) +GENERATE_STATIC_LIST_DELETE(deleteTeam, flib_team*) + +static int findTeam(const flib_teamlist *list, const char *name) { + for(int i=0; iteamCount; i++) { + if(!strcmp(name, list->teams[i]->name)) { + return i; + } + } + return -1; +} + +int flib_teamlist_insert(flib_teamlist *list, flib_team *team, int pos) { + if(!list || !team) { + flib_log_e("null parameter in flib_teamlist_insert"); + } else if(!insertTeam(&list->teams, &list->teamCount, team, pos)) { + flib_team_retain(team); + return 0; + } + return -1; +} + +int flib_teamlist_delete(flib_teamlist *list, const char *name) { + int result = -1; + if(!list || !name) { + flib_log_e("null parameter in flib_teamlist_delete"); + } else { + int itemid = findTeam(list, name); + if(itemid>=0) { + flib_team *team = list->teams[itemid]; + if(!deleteTeam(&list->teams, &list->teamCount, itemid)) { + flib_team_release(team); + result = 0; + } + } + } + return result; +} + +flib_team *flib_teamlist_find(const flib_teamlist *list, const char *name) { + flib_team *result = NULL; + if(!list || !name) { + flib_log_e("null parameter in flib_teamlist_find"); + } else { + int itemid = findTeam(list, name); + if(itemid>=0) { + result = list->teams[itemid]; + } + } + return result; +} + +void flib_teamlist_clear(flib_teamlist *list) { + if(!list) { + flib_log_e("null parameter in flib_teamlist_clear"); + } else { + for(int i=0; iteamCount; i++) { + flib_team_release(list->teams[i]); + } + free(list->teams); + list->teams = NULL; + list->teamCount = 0; + } +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/teamlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/model/teamlist.h Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,36 @@ +#ifndef TEAMLIST_H_ +#define TEAMLIST_H_ + +#include "team.h" + +typedef struct { + int teamCount; + flib_team **teams; +} flib_teamlist; + +flib_teamlist *flib_teamlist_create(); + +void flib_teamlist_destroy(flib_teamlist *list); + +/** + * Insert a team into the list. Returns 0 on success. + */ +int flib_teamlist_insert(flib_teamlist *list, flib_team *team, int pos); + +/** + * Delete the item with the name [name] from the list. + * Returns 0 on success. + */ +int flib_teamlist_delete(flib_teamlist *list, const char *name); + +/** + * Returns the team with the name [name] from the list if it exists, NULL otherwise + */ +flib_team *flib_teamlist_find(const flib_teamlist *list, const char *name); + +/** + * Removes all items from the list and frees "teams". + */ +void flib_teamlist_clear(flib_teamlist *list); + +#endif diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/weapon.c --- a/project_files/frontlib/model/weapon.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/weapon.c Wed Jun 27 18:02:45 2012 +0200 @@ -72,11 +72,28 @@ } } +flib_weaponset *flib_weaponset_copy(const flib_weaponset *weaponset) { + if(!weaponset) { + return NULL; + } + + flib_weaponset *result = flib_weaponset_create(weaponset->name); + if(result) { + memcpy(result->loadout, weaponset->loadout, WEAPONS_COUNT+1); + memcpy(result->crateprob, weaponset->crateprob, WEAPONS_COUNT+1); + memcpy(result->delay, weaponset->delay, WEAPONS_COUNT+1); + memcpy(result->crateammo, weaponset->crateammo, WEAPONS_COUNT+1); + } + + return result; +} + static void flib_weaponsetlist_destroy(flib_weaponsetlist *list) { if(list) { for(int i=0; iweaponsetCount; i++) { flib_weaponset_release(list->weaponsets[i]); } + free(list->weaponsets); free(list); } } @@ -196,31 +213,30 @@ return flib_weaponsetlist_retain(flib_calloc(1, sizeof(flib_weaponsetlist))); } +GENERATE_STATIC_LIST_INSERT(insertWeaponset, flib_weaponset*) +GENERATE_STATIC_LIST_DELETE(deleteWeaponset, flib_weaponset*) + int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *set, int pos) { - flib_weaponset **changedList = flib_list_insert(list->weaponsets, &list->weaponsetCount, sizeof(*list->weaponsets), &set, pos); - if(changedList) { - list->weaponsets = changedList; + if(!list) { + flib_log_e("Invalid parameter in flib_weaponsetlist_insert"); + } else if(!insertWeaponset(&list->weaponsets, &list->weaponsetCount, set, pos)) { flib_weaponset_retain(set); return 0; - } else { - return -1; } + return -1; } int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos) { - int result = -1; - if(!list || pos<0 || pos>=list->weaponsetCount) { + if(!list) { flib_log_e("Invalid parameter in flib_weaponsetlist_delete"); } else { flib_weaponset *elem = list->weaponsets[pos]; - flib_weaponset **changedList = flib_list_delete(list->weaponsets, &list->weaponsetCount, sizeof(*list->weaponsets), pos); - if(changedList || list->weaponsetCount==0) { - list->weaponsets = changedList; + if(!deleteWeaponset(&list->weaponsets, &list->weaponsetCount, pos)) { flib_weaponset_release(elem); - result = 0; + return 0; } } - return result; + return -1; } flib_weaponsetlist *flib_weaponsetlist_retain(flib_weaponsetlist *list) { diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/model/weapon.h --- a/project_files/frontlib/model/weapon.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/model/weapon.h Wed Jun 27 18:02:45 2012 +0200 @@ -44,6 +44,8 @@ */ void flib_weaponset_release(flib_weaponset *weaponset); +flib_weaponset *flib_weaponset_copy(const flib_weaponset *weaponset); + /** * Create a weaponset from an ammostring. This format is used both in the ini files * and in the net protocol. diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netbase.c --- a/project_files/frontlib/net/netbase.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netbase.c Wed Jun 27 18:02:45 2012 +0200 @@ -105,8 +105,7 @@ return 0; } else { int size = flib_socket_nbrecv(net->sock, buffer, sizeof(buffer)); - if(size>=0) { - flib_vector_append(net->readBuffer, buffer, size); + if(size>=0 && !flib_vector_append(net->readBuffer, buffer, size)) { return size; } else { flib_socket_close(net->sock); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netconn.c --- a/project_files/frontlib/net/netconn.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netconn.c Wed Jun 27 18:02:45 2012 +0200 @@ -27,31 +27,44 @@ #include "../model/roomlist.h" #include "../md5/md5.h" #include "../base64/base64.h" +#include "../model/mapcfg.h" #include #include #include #include -flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port) { +flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *dataDirPath, const char *host, uint16_t port) { flib_netconn *result = NULL; if(!playerName || !metacfg || !host) { flib_log_e("null parameter in flib_netconn_create"); } else { flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn)); if(newConn) { + newConn->netBase = flib_netbase_create(host, port); + newConn->playerName = flib_strdupnull(playerName); + newConn->dataDirPath = flib_strdupnull(dataDirPath); + newConn->netconnState = NETCONN_STATE_CONNECTING; newConn->isAdmin = false; + newConn->metaCfg = flib_cfg_meta_retain(metacfg); + newConn->roomList.roomCount = 0; + newConn->roomList.rooms = NULL; + newConn->isChief = false; - newConn->metaCfg = flib_cfg_meta_retain(metacfg); - newConn->roomList = flib_roomlist_create(); newConn->map = flib_map_create_named("", "NoSuchMap"); + newConn->pendingTeamlist.teamCount = 0; + newConn->pendingTeamlist.teams = NULL; + newConn->teamlist.teamCount = 0; + newConn->teamlist.teams = NULL; + newConn->scheme = NULL; + newConn->script = NULL; + newConn->weaponset = NULL; + newConn->running = false; newConn->destroyRequested = false; - clearCallbacks(newConn); - newConn->netBase = flib_netbase_create(host, port); - newConn->playerName = flib_strdupnull(playerName); - if(newConn->netBase && newConn->playerName && newConn->roomList) { + netconn_clearCallbacks(newConn); + if(newConn->netBase && newConn->playerName && newConn->dataDirPath && newConn->map) { result = newConn; newConn = NULL; } @@ -69,14 +82,23 @@ * and we delay the actual destruction. We ensure no further callbacks will be * sent to prevent surprises. */ - clearCallbacks(conn); + netconn_clearCallbacks(conn); conn->destroyRequested = true; } else { flib_netbase_destroy(conn->netBase); + free(conn->playerName); + free(conn->dataDirPath); + flib_cfg_meta_release(conn->metaCfg); - flib_roomlist_destroy(conn->roomList); + flib_roomlist_clear(&conn->roomList); + flib_map_release(conn->map); - free(conn->playerName); + flib_teamlist_clear(&conn->pendingTeamlist); + flib_teamlist_clear(&conn->teamlist); + flib_cfg_release(conn->scheme); + free(conn->script); + flib_weaponset_release(conn->weaponset); + free(conn); } } @@ -87,7 +109,7 @@ if(!conn) { flib_log_e("null parameter in flib_netconn_get_roomlist"); } else { - result = conn->roomList; + result = &conn->roomList; } return result; } @@ -102,16 +124,92 @@ return result; } -void leaveRoom(flib_netconn *conn) { +void netconn_leaveRoom(flib_netconn *conn) { conn->netconnState = NETCONN_STATE_LOBBY; conn->isChief = false; - flib_map *map = flib_map_create_named("", "NoSuchMap"); - if(map) { + flib_map_release(conn->map); + conn->map = flib_map_create_named("", "NoSuchMap"); + flib_teamlist_clear(&conn->pendingTeamlist); + flib_teamlist_clear(&conn->teamlist); + flib_cfg_release(conn->scheme); + conn->scheme = NULL; + free(conn->script); + conn->script = NULL; + flib_weaponset_release(conn->weaponset); + conn->weaponset = NULL; +} + +bool flib_netconn_is_in_room_context(flib_netconn *conn) { + return conn && (conn->netconnState == NETCONN_STATE_ROOM || conn->netconnState == NETCONN_STATE_INGAME); +} + +void netconn_setMap(flib_netconn *conn, const flib_map *map) { + flib_map *copy = flib_map_copy(map); + if(copy) { flib_map_release(conn->map); - conn->map = map; + conn->map = copy; + } +} + +void netconn_setWeaponset(flib_netconn *conn, const flib_weaponset *weaponset) { + flib_weaponset *copy = flib_weaponset_copy(weaponset); + if(copy) { + flib_weaponset_release(conn->weaponset); + conn->weaponset = copy; + } +} + +void netconn_setScript(flib_netconn *conn, const char *script) { + char *copy = flib_strdupnull(script); + if(copy) { + free(conn->script); + conn->script = copy; + } +} + +void netconn_setScheme(flib_netconn *conn, const flib_cfg *scheme) { + flib_cfg *copy = flib_cfg_copy(scheme); + if(copy) { + flib_cfg_release(conn->scheme); + conn->scheme = copy; + } +} + +flib_gamesetup *flib_netconn_create_gameSetup(flib_netconn *conn) { + flib_gamesetup *result = NULL; + if(!conn) { + flib_log_e("null parameter in flib_netconn_create_gameSetup"); } else { - flib_log_e("Error resetting netconn.map"); + if(conn->teamlist.teamCount==0 || !conn->scheme || !conn->weaponset) { + flib_log_e("Incomplete room state to create game setup."); + } else { + result = flib_calloc(1, sizeof(flib_gamesetup)); + if(result) { + result->gamescheme = flib_cfg_copy(conn->scheme); + result->map = flib_map_copy(conn->map); + result->script = flib_strdupnull(conn->script); + result->teamlist = flib_teamlist_create(); + for(int i=0; iteamlist.teamCount; i++) { + flib_team *copy = flib_team_copy(conn->teamlist.teams[i]); + if(copy) { + flib_team_set_weaponset(copy, conn->weaponset); + flib_team_set_health(copy, conn->scheme->settings[2]); // TODO by name + flib_teamlist_insert(result->teamlist, copy, result->teamlist->teamCount); + } + flib_team_release(copy); + } + if(result->map->mapgen == MAPGEN_NAMED && result->map->name) { + flib_mapcfg mapcfg; + if(!flib_mapcfg_read(conn->dataDirPath, result->map->name, &mapcfg)) { + free(result->map->theme); + result->map->theme = flib_strdupnull(mapcfg.theme); + } + } + // TODO handle errors + } + } } + return result; } static void flib_netconn_wrappedtick(flib_netconn *conn) { @@ -184,9 +282,9 @@ if(netmsg->partCount % 8 != 1) { flib_log_w("Net: Malformed ROOMS message"); } else { - flib_roomlist_clear(conn->roomList); + flib_roomlist_clear(&conn->roomList); for(int i=1; ipartCount; i+=8) { - if(flib_roomlist_add(conn->roomList, netmsg->parts+i)) { + if(flib_roomlist_add(&conn->roomList, netmsg->parts+i)) { flib_log_e("Error adding room to list in ROOMS message"); } } @@ -233,7 +331,7 @@ switch(flags[i]) { case 'r': for(int j = 2; j < netmsg->partCount; ++j) { - conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[i], setFlag); + conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[j], setFlag); } break; default: @@ -243,31 +341,36 @@ } } } else if (!strcmp(cmd, "ADD_TEAM")) { - if(netmsg->partCount != 24) { + if(netmsg->partCount != 24 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad ADD_TEAM message"); } else { flib_team *team = flib_team_from_netmsg(netmsg->parts+1); - if(!team) { + flib_team *teamcopy = flib_team_from_netmsg(netmsg->parts+1); + if(!team || !teamcopy) { conn->netconnState = NETCONN_STATE_DISCONNECTED; conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error"); exit = true; } else { team->remoteDriven = true; + teamcopy->remoteDriven = true; + flib_teamlist_insert(&conn->teamlist, teamcopy, conn->teamlist.teamCount); conn->onTeamAddCb(conn->onTeamAddCtx, team); } flib_team_release(team); + flib_team_release(teamcopy); } } else if (!strcmp(cmd, "REMOVE_TEAM")) { - if(netmsg->partCount != 2) { + if(netmsg->partCount != 2 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad REMOVETEAM message"); } else { + flib_teamlist_delete(&conn->teamlist, netmsg->parts[1]); conn->onTeamDeleteCb(conn->onTeamDeleteCtx, netmsg->parts[1]); } } else if(!strcmp(cmd, "ROOMABANDONED")) { - leaveRoom(conn); + netconn_leaveRoom(conn); conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed"); } else if(!strcmp(cmd, "KICKED")) { - leaveRoom(conn); + netconn_leaveRoom(conn); conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked"); } else if(!strcmp(cmd, "JOINED")) { if(netmsg->partCount < 2) { @@ -312,19 +415,19 @@ } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) { const char *subcmd = netmsg->parts[1]; if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) { - if(flib_roomlist_add(conn->roomList, netmsg->parts+2)) { + if(flib_roomlist_add(&conn->roomList, netmsg->parts+2)) { flib_log_e("Error adding new room to list"); } else { - conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList->rooms[0]); + conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList.rooms[0]); } } else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) { - if(flib_roomlist_update(conn->roomList, netmsg->parts[2], netmsg->parts+3)) { + if(flib_roomlist_update(&conn->roomList, netmsg->parts[2], netmsg->parts+3)) { flib_log_e("Error updating room in list"); } else { - conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(conn->roomList, netmsg->parts[2])); + conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(&conn->roomList, netmsg->parts[2])); } } else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) { - if(flib_roomlist_delete(conn->roomList, netmsg->parts[2])) { + if(flib_roomlist_delete(&conn->roomList, netmsg->parts[2])) { flib_log_e("Error deleting room from list"); } else { conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]); @@ -340,6 +443,7 @@ } } else if (!strcmp(cmd, "RUN_GAME")) { conn->netconnState = NETCONN_STATE_INGAME; + // TODO send along the config conn->onRunGameCb(conn->onRunGameCtx); } else if (!strcmp(cmd, "ASKPASSWORD")) { conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName); @@ -358,19 +462,27 @@ } } } else if (!strcmp(cmd, "TEAM_ACCEPTED")) { - if (netmsg->partCount != 2) { + if (netmsg->partCount != 2 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad TEAM_ACCEPTED message"); } else { + flib_team *team = flib_teamlist_find(&conn->pendingTeamlist, netmsg->parts[1]); + if(team) { + flib_teamlist_insert(&conn->teamlist, team, conn->teamlist.teamCount); + flib_teamlist_delete(&conn->pendingTeamlist, netmsg->parts[1]); + } else { + flib_log_e("Team accepted that was not requested: %s", netmsg->parts[1]); + } conn->onTeamAcceptedCb(conn->onTeamAcceptedCtx, netmsg->parts[1]); } } else if (!strcmp(cmd, "CFG")) { - if(netmsg->partCount < 3) { + if(netmsg->partCount < 3 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad CFG message"); } else { const char *subcmd = netmsg->parts[1]; if(!strcmp(subcmd, "SCHEME") && netmsg->partCount == conn->metaCfg->modCount + conn->metaCfg->settingCount + 3) { flib_cfg *cfg = flib_netmsg_to_cfg(conn->metaCfg, netmsg->parts+2); if(cfg) { + netconn_setScheme(conn, cfg); conn->onCfgSchemeCb(conn->onCfgSchemeCtx, cfg); } else { flib_log_e("Error processing CFG SCHEME message"); @@ -379,12 +491,12 @@ } else if(!strcmp(subcmd, "FULLMAPCONFIG") && netmsg->partCount == 7) { flib_map *map = flib_netmsg_to_map(netmsg->parts+2); if(map) { - flib_map_release(conn->map); - conn->map = map; + netconn_setMap(conn, map); conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_FULL); } else { flib_log_e("Error processing CFG FULLMAPCONFIG message"); } + flib_map_release(map); } else if(!strcmp(subcmd, "MAP") && netmsg->partCount == 3) { char *mapname = flib_strdupnull(netmsg->parts[2]); if(mapname) { @@ -423,8 +535,8 @@ conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAZE_SIZE); } else if(!strcmp(subcmd, "DRAWNMAP") && netmsg->partCount == 3) { size_t drawnMapSize = 0; - uint8_t *drawnMapData = flib_netmsg_to_drawnmapdata(&drawnMapSize, netmsg->parts[2]); - if(drawnMapData) { + uint8_t *drawnMapData = NULL; + if(!flib_netmsg_to_drawnmapdata(netmsg->parts[2], &drawnMapData, &drawnMapSize)) { free(conn->map->drawData); conn->map->drawData = drawnMapData; conn->map->drawDataSize = drawnMapSize; @@ -433,10 +545,12 @@ flib_log_e("Error processing CFG DRAWNMAP message"); } } else if(!strcmp(subcmd, "SCRIPT") && netmsg->partCount == 3) { + netconn_setScript(conn, netmsg->parts[2]); conn->onScriptChangedCb(conn->onScriptChangedCtx, netmsg->parts[2]); } else if(!strcmp(subcmd, "AMMO") && netmsg->partCount == 4) { flib_weaponset *weapons = flib_weaponset_from_ammostring(netmsg->parts[2], netmsg->parts[3]); if(weapons) { + netconn_setWeaponset(conn, weapons); conn->onWeaponsetChangedCb(conn->onWeaponsetChangedCtx, weapons); } else { flib_log_e("Error processing CFG AMMO message"); @@ -447,23 +561,35 @@ } } } else if (!strcmp(cmd, "HH_NUM")) { - if (netmsg->partCount != 3) { + if (netmsg->partCount != 3 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad HH_NUM message"); } else { int hogs = atoi(netmsg->parts[2]); if(hogs<=0 || hogs>HEDGEHOGS_PER_TEAM) { flib_log_w("Net: Bad HH_NUM message: %s hogs", netmsg->parts[2]); } else { + flib_team *team = flib_teamlist_find(&conn->teamlist, netmsg->parts[1]); + if(team) { + team->hogsInGame = hogs; + } else { + flib_log_e("HH_NUM message for unknown team %s", netmsg->parts[1]); + } conn->onHogCountChangedCb(conn->onHogCountChangedCtx, netmsg->parts[1], hogs); } } } else if (!strcmp(cmd, "TEAM_COLOR")) { - if (netmsg->partCount != 3) { + if (netmsg->partCount != 3 || !flib_netconn_is_in_room_context(conn)) { flib_log_w("Net: Bad TEAM_COLOR message"); } else { long color; - if(sscanf(netmsg->parts[2], "#%lx", &color)) { - conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], (uint32_t)color); + if(sscanf(netmsg->parts[2], "%lu", &color) && color>=0 && colorteamlist, netmsg->parts[1]); + if(team) { + team->colorIndex = color; + } else { + flib_log_e("TEAM_COLOR message for unknown team %s", netmsg->parts[1]); + } + conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], color); } else { flib_log_w("Net: Bad TEAM_COLOR message: Color %s", netmsg->parts[2]); } @@ -477,7 +603,7 @@ size_t outlen; bool ok = base64_decode_alloc(netmsg->parts[i], strlen(netmsg->parts[i]), &out, &outlen); if(ok && outlen) { - conn->onEngineMessageCb(conn->onEngineMessageCtx, out, outlen); + conn->onEngineMessageCb(conn->onEngineMessageCtx, (uint8_t*)out, outlen); } else { flib_log_e("Net: Malformed engine message: %s", netmsg->parts[i]); } diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netconn.h --- a/project_files/frontlib/net/netconn.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netconn.h Wed Jun 27 18:02:45 2012 +0200 @@ -40,7 +40,11 @@ // TODO: Order of functions, and match the order in netconn.c typedef struct _flib_netconn flib_netconn; -flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port); +/** + * Create a new netplay connection with these parameters. + * The path to the data directory must end with a path delimiter (e.g. C:\Games\Hedgewars\Data\) + */ +flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *dataDirPath, const char *host, uint16_t port); void flib_netconn_destroy(flib_netconn *conn); /** @@ -62,6 +66,20 @@ bool flib_netconn_is_chief(flib_netconn *conn); /** + * Are you in the context of a room, i.e. either in room or ingame state? + */ +bool flib_netconn_is_in_room_context(flib_netconn *conn); + +/** + * Generate a game setup from the current room state. + * Returns NULL if the room state does not contain enough information + * for a complete game setup, or if an error occurs. + * + * The new gamesetup must be destroyed TODO function for that... + */ +flib_gamesetup *flib_netconn_create_gameSetup(flib_netconn *conn); + +/** * quitmsg may be null */ int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg); @@ -146,7 +164,7 @@ * Set the teamcolor of a team. Only makes sense in room state and if you are chief. * The server does not send a reply. */ -int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, uint32_t colorRGB); +int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, int colorIndex); /** * Set the weaponset for the room. Only makes sense in room state and if you are chief. @@ -318,9 +336,9 @@ * flib_netconn_get_roomlist() as soon as the onConnected callback is fired. These callbacks * provide notification about changes. */ -void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_roomlist_room *room), void* context); +void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_room *room), void* context); void flib_netconn_onRoomDelete(flib_netconn *conn, void (*callback)(void *context, const char *name), void* context); -void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_roomlist_room *room), void* context); +void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_room *room), void* context); /** * Callbacks for players joining or leaving the lobby. If join is true it's a join, otherwise a leave. @@ -417,9 +435,9 @@ * The color of a team has been changed by the room chief. If you are the chief and change the color yourself, * you will not receive this callback! */ -void flib_netconn_onTeamColorChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, uint32_t colorARGB), void *context); +void flib_netconn_onTeamColorChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, int colorIndex), void *context); -void flib_netconn_onEngineMessage(flib_netconn *conn, void (*callback)(void *context, const char *message, int size), void *context); +void flib_netconn_onEngineMessage(flib_netconn *conn, void (*callback)(void *context, const uint8_t *message, size_t size), void *context); void flib_netconn_onCfgScheme(flib_netconn *conn, void (*callback)(void *context, flib_cfg *scheme), void *context); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netconn_callbacks.c --- a/project_files/frontlib/net/netconn_callbacks.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netconn_callbacks.c Wed Jun 27 18:02:45 2012 +0200 @@ -41,7 +41,7 @@ flib_netconn_send_quit((flib_netconn*)context, "Authentication failed"); } -void clearCallbacks(flib_netconn *conn) { +void netconn_clearCallbacks(flib_netconn *conn) { flib_netconn_onMessage(conn, NULL, NULL); flib_netconn_onConnected(conn, NULL, NULL); flib_netconn_onDisconnected(conn, NULL, NULL); @@ -102,9 +102,9 @@ GENERATE_CB_SETTER(onMessage, (void *context, int msgtype, const char *msg), defaultCallback_onMessage); GENERATE_CB_SETTER_AND_DEFAULT(onConnected, (void *context)); GENERATE_CB_SETTER_AND_DEFAULT(onDisconnected, (void *context, int reason, const char *message)); -GENERATE_CB_SETTER_AND_DEFAULT(onRoomAdd, (void *context, const flib_roomlist_room *room)); +GENERATE_CB_SETTER_AND_DEFAULT(onRoomAdd, (void *context, const flib_room *room)); GENERATE_CB_SETTER_AND_DEFAULT(onRoomDelete, (void *context, const char *name)); -GENERATE_CB_SETTER_AND_DEFAULT(onRoomUpdate, (void *context, const char *oldName, const flib_roomlist_room *room)); +GENERATE_CB_SETTER_AND_DEFAULT(onRoomUpdate, (void *context, const char *oldName, const flib_room *room)); GENERATE_CB_SETTER(onChat, (void *context, const char *nick, const char *msg), defaultCallback_onChat); GENERATE_CB_SETTER_AND_DEFAULT(onLobbyJoin, (void *context, const char *nick)); GENERATE_CB_SETTER_AND_DEFAULT(onLobbyLeave, (void *context, const char *nick, const char *partMsg)); @@ -121,8 +121,8 @@ GENERATE_CB_SETTER_AND_DEFAULT(onRunGame, (void *context)); GENERATE_CB_SETTER_AND_DEFAULT(onTeamAccepted, (void *context, const char *teamName)); GENERATE_CB_SETTER_AND_DEFAULT(onHogCountChanged, (void *context, const char *teamName, int hogs)); -GENERATE_CB_SETTER_AND_DEFAULT(onTeamColorChanged, (void *context, const char *teamName, uint32_t colorRGB)); -GENERATE_CB_SETTER_AND_DEFAULT(onEngineMessage, (void *context, const char *message, int size)); +GENERATE_CB_SETTER_AND_DEFAULT(onTeamColorChanged, (void *context, const char *teamName, int colorIndex)); +GENERATE_CB_SETTER_AND_DEFAULT(onEngineMessage, (void *context, const uint8_t *message, size_t size)); GENERATE_CB_SETTER_AND_DEFAULT(onCfgScheme, (void *context, flib_cfg *scheme)); GENERATE_CB_SETTER_AND_DEFAULT(onMapChanged, (void *context, const flib_map *map, int changetype)); GENERATE_CB_SETTER_AND_DEFAULT(onScriptChanged, (void *context, const char *script)); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netconn_internal.h --- a/project_files/frontlib/net/netconn_internal.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netconn_internal.h Wed Jun 27 18:02:45 2012 +0200 @@ -20,14 +20,21 @@ struct _flib_netconn { flib_netbase *netBase; char *playerName; + char *dataDirPath; + + int netconnState; // One of the NETCONN_STATE constants + bool isAdmin; // Player is server administrator + flib_cfg_meta *metaCfg; - flib_roomlist *roomList; + flib_roomlist roomList; - int netconnState; // One of the NETCONN_STATE constants - - bool isAdmin; // Player is server administrator - bool isChief; // Player can modify the current room - flib_map *map; // Map settings in the current room. + bool isChief; // Player can modify the current room + flib_map *map; + flib_teamlist pendingTeamlist; + flib_teamlist teamlist; + flib_cfg *scheme; + char *script; + flib_weaponset *weaponset; void (*onMessageCb)(void *context, int msgtype, const char *msg); void *onMessageCtx; @@ -38,13 +45,13 @@ void (*onDisconnectedCb)(void *context, int reason, const char *message); void *onDisconnectedCtx; - void (*onRoomAddCb)(void *context, const flib_roomlist_room *room); + void (*onRoomAddCb)(void *context, const flib_room *room); void *onRoomAddCtx; void (*onRoomDeleteCb)(void *context, const char *name); void *onRoomDeleteCtx; - void (*onRoomUpdateCb)(void *context, const char *oldName, const flib_roomlist_room *room); + void (*onRoomUpdateCb)(void *context, const char *oldName, const flib_room *room); void *onRoomUpdateCtx; void (*onChatCb)(void *context, const char *nick, const char *msg); @@ -95,10 +102,10 @@ void (*onHogCountChangedCb)(void *context, const char *teamName, int hogs); void *onHogCountChangedCtx; - void (*onTeamColorChangedCb)(void *context, const char *teamName, uint32_t colorRGB); + void (*onTeamColorChangedCb)(void *context, const char *teamName, int colorIndex); void *onTeamColorChangedCtx; - void (*onEngineMessageCb)(void *context, const char *message, int size); + void (*onEngineMessageCb)(void *context, const uint8_t *message, size_t size); void *onEngineMessageCtx; void (*onCfgSchemeCb)(void *context, flib_cfg *scheme); @@ -123,6 +130,11 @@ bool destroyRequested; }; -void clearCallbacks(flib_netconn *conn); +void netconn_clearCallbacks(flib_netconn *conn); +void netconn_leaveRoom(flib_netconn *conn); +void netconn_setMap(flib_netconn *conn, const flib_map *map); +void netconn_setWeaponset(flib_netconn *conn, const flib_weaponset *weaponset); +void netconn_setScript(flib_netconn *conn, const char *script); +void netconn_setScheme(flib_netconn *conn, const flib_cfg *scheme); #endif diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netconn_send.c --- a/project_files/frontlib/net/netconn_send.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netconn_send.c Wed Jun 27 18:02:45 2012 +0200 @@ -10,50 +10,50 @@ #include #include -// TODO state changes - // cmdname is always given as literal from functions in this file, so it is never null. static int sendVoid(flib_netconn *conn, const char *cmdname) { - if(!conn) { - flib_log_e("null parameter trying to send %s command.", cmdname); + if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) { return -1; } return flib_netbase_sendf(conn->netBase, "%s\n\n", cmdname); } +// Testing for !*str prevents sending 0-length parameters (they trip up the protocol) static int sendStr(flib_netconn *conn, const char *cmdname, const char *str) { - if(!conn || !str) { - flib_log_e("null parameter trying to send %s command.", cmdname); + if(log_e_if(!conn || !str || !*str, "Invalid parameter sending %s command", cmdname)) { return -1; } return flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", cmdname, str); } static int sendInt(flib_netconn *conn, const char *cmdname, int param) { - if(!conn) { - flib_log_e("null parameter trying to send %s command.", cmdname); + if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) { return -1; } return flib_netbase_sendf(conn->netBase, "%s\n%i\n\n", cmdname, param); } int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) { - return sendStr(conn, "QUIT", quitmsg ? quitmsg : "User quit"); + return sendStr(conn, "QUIT", (quitmsg && *quitmsg) ? quitmsg : "User quit"); } int flib_netconn_send_chat(flib_netconn *conn, const char *chat) { - return sendStr(conn, "CHAT", chat); + if(chat && *chat) { + return sendStr(conn, "CHAT", chat); + } + return 0; } int flib_netconn_send_teamchat(flib_netconn *conn, const char *chat) { - return sendStr(conn, "TEAMCHAT", chat); + if(chat && *chat) { + return sendStr(conn, "TEAMCHAT", chat); + } + return 0; } int flib_netconn_send_nick(flib_netconn *conn, const char *nick) { int result = -1; - if(!conn || !nick) { - flib_log_e("null parameter in flib_netconn_send_nick"); - } else { + if(!log_badparams_if(!conn || !nick || !*nick)) { char *tmpName = flib_strdupnull(nick); if(tmpName) { if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) { @@ -70,9 +70,7 @@ int flib_netconn_send_password(flib_netconn *conn, const char *latin1Passwd) { int result = -1; - if(!conn || !latin1Passwd) { - flib_log_e("null parameter in flib_netconn_send_password"); - } else { + if(!log_badparams_if(!conn || !latin1Passwd)) { md5_state_t md5state; uint8_t md5bytes[16]; char md5hex[33]; @@ -89,11 +87,19 @@ } int flib_netconn_send_joinRoom(flib_netconn *conn, const char *room) { - return sendStr(conn, "JOIN_ROOM", room); + if(!sendStr(conn, "JOIN_ROOM", room)) { + conn->isChief = false; + return 0; + } + return -1; } int flib_netconn_send_createRoom(flib_netconn *conn, const char *room) { - return sendStr(conn, "CREATE_ROOM", room); + if(!sendStr(conn, "CREATE_ROOM", room)) { + conn->isChief = true; + return 0; + } + return -1; } int flib_netconn_send_renameRoom(flib_netconn *conn, const char *roomName) { @@ -101,35 +107,50 @@ } int flib_netconn_send_leaveRoom(flib_netconn *conn) { - return sendVoid(conn, "PART"); + if(flib_netconn_is_in_room_context(conn) && !sendVoid(conn, "PART")) { + netconn_leaveRoom(conn); + return 0; + } + return -1; } int flib_netconn_send_toggleReady(flib_netconn *conn) { return sendVoid(conn, "TOGGLE_READY"); } +static void addTeamToPendingList(flib_netconn *conn, const flib_team *team) { + flib_team *teamcopy = flib_team_copy(team); + if(teamcopy) { + teamcopy->remoteDriven = false; + free(teamcopy->ownerName); + teamcopy->ownerName = flib_strdupnull(conn->playerName); + if(teamcopy->ownerName) { + flib_teamlist_delete(&conn->pendingTeamlist, team->name); + flib_teamlist_insert(&conn->pendingTeamlist, teamcopy, 0); + } + } + flib_team_release(teamcopy); +} + int flib_netconn_send_addTeam(flib_netconn *conn, const flib_team *team) { int result = -1; - if(!conn || !team) { - flib_log_e("null parameter in flib_netconn_send_addTeam"); - } else { - bool missingInfo = !team->name || !team->color || !team->grave || !team->fort || !team->voicepack || !team->flag; + if(!log_badparams_if(!conn || !team)) { + bool missingInfo = !team->name || !team->grave || !team->fort || !team->voicepack || !team->flag; for(int i=0; ihogs[i].name || !team->hogs[i].hat; } - if(missingInfo) { - flib_log_e("Incomplete team definition for flib_netconn_send_addTeam"); - } else { + if(!log_e_if(missingInfo, "Incomplete team definition")) { flib_vector *vec = flib_vector_create(); if(vec) { bool error = false; - error |= flib_vector_appendf(vec, "ADD_TEAM\n%s\n%lu\n%s\n%s\n%s\n%s\n%i\n", team->name, (unsigned long)team->color, team->grave, team->fort, team->voicepack, team->flag, team->hogs[0].difficulty); + error |= flib_vector_appendf(vec, "ADD_TEAM\n%s\n%i\n%s\n%s\n%s\n%s\n%i\n", team->name, team->colorIndex, team->grave, team->fort, team->voicepack, team->flag, team->hogs[0].difficulty); for(int i=0; ihogs[i].name, team->hogs[i].hat); } error |= flib_vector_appendf(vec, "\n"); - if(!error) { - result = flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec)); + if(!error && !flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec))) { + addTeamToPendingList(conn, team); + result = 0; } } flib_vector_destroy(vec); @@ -139,14 +160,19 @@ } int flib_netconn_send_removeTeam(flib_netconn *conn, const char *teamname) { - return sendStr(conn, "REMOVE_TEAM", teamname); + if(!sendStr(conn, "REMOVE_TEAM", teamname)) { + flib_team *team = flib_teamlist_find(&conn->teamlist, teamname); + if(team && !team->remoteDriven) { + flib_teamlist_delete(&conn->teamlist, teamname); + } + return 0; + } + return -1; } int flib_netconn_send_engineMessage(flib_netconn *conn, const uint8_t *message, size_t size) { int result = -1; - if(!conn || (!message && size>0)) { - flib_log_e("null parameter in flib_netconn_send_engineMessage"); - } else { + if(!log_badparams_if(!conn || (!message && size>0))) { char *base64encout = NULL; base64_encode_alloc((const char*)message, size, &base64encout); if(base64encout) { @@ -158,38 +184,52 @@ } int flib_netconn_send_teamHogCount(flib_netconn *conn, const char *teamname, int hogcount) { - if(!conn || !teamname || hogcount<1 || hogcount>HEDGEHOGS_PER_TEAM) { - flib_log_e("invalid parameter in flib_netconn_send_teamHogCount"); - return -1; + if(!log_badparams_if(!conn || !teamname || hogcount<1 || hogcount>HEDGEHOGS_PER_TEAM) + && !flib_netbase_sendf(conn->netBase, "HH_NUM\n%s\n%i\n\n", teamname, hogcount)) { + if(conn->isChief) { + flib_team *team = flib_teamlist_find(&conn->teamlist, teamname); + if(team) { + team->hogsInGame = hogcount; + } + } + return 0; } - return flib_netbase_sendf(conn->netBase, "HH_NUM\n%s\n%i\n\n", teamname, hogcount); + return -1; } -int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, uint32_t colorRGB) { - if(!conn || !teamname) { - flib_log_e("null parameter in flib_netconn_send_teamColor"); - return -1; +int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, int colorIndex) { + if(!log_badparams_if(!conn || !teamname) + && !flib_netbase_sendf(conn->netBase, "TEAM_COLOR\n%s\n%i\n\n", teamname, colorIndex)) { + if(conn->isChief) { + flib_team *team = flib_teamlist_find(&conn->teamlist, teamname); + if(team) { + team->colorIndex = colorIndex; + } + } + return 0; } - return flib_netbase_sendf(conn->netBase, "TEAM_COLOR\n%s\n%lu\n\n", teamname, (unsigned long)colorRGB); + return -1; } int flib_netconn_send_weaponset(flib_netconn *conn, const flib_weaponset *weaponset) { - if(!conn || !weaponset) { - flib_log_e("null parameter in flib_netconn_send_weaponset"); - return -1; + if(!log_badparams_if(!conn || !weaponset)) { + char ammostring[WEAPONS_COUNT*4+1]; + strcpy(ammostring, weaponset->loadout); + strcat(ammostring, weaponset->crateprob); + strcat(ammostring, weaponset->delay); + strcat(ammostring, weaponset->crateammo); + if(!flib_netbase_sendf(conn->netBase, "CFG\nAMMO\n%s\n%s\n\n", weaponset->name, ammostring)) { + if(conn->isChief) { + netconn_setWeaponset(conn, weaponset); + } + return 0; + } } - - char ammostring[WEAPONS_COUNT*4+1]; - strcpy(ammostring, weaponset->loadout); - strcat(ammostring, weaponset->crateprob); - strcat(ammostring, weaponset->delay); - strcat(ammostring, weaponset->crateammo); - return flib_netbase_sendf(conn->netBase, "CFG\nAMMO\n%s\n%s\n\n", weaponset->name, ammostring); + return -1; } int flib_netconn_send_map(flib_netconn *conn, const flib_map *map) { - if(!conn || !map) { - flib_log_e("null parameter in flib_netconn_send_map"); + if(log_badparams_if(!conn || !map)) { return -1; } bool error = false; @@ -213,34 +253,80 @@ } int flib_netconn_send_mapName(flib_netconn *conn, const char *mapName) { - return sendStr(conn, "CFG\nMAP", mapName); + if(!sendStr(conn, "CFG\nMAP", mapName)) { + if(conn->isChief) { + char *copy = flib_strdupnull(mapName); + if(copy) { + free(conn->map->name); + conn->map->name = copy; + } + } + return 0; + } + return -1; } int flib_netconn_send_mapGen(flib_netconn *conn, int mapGen) { - return sendInt(conn, "CFG\nMAPGEN", mapGen); + if(!sendInt(conn, "CFG\nMAPGEN", mapGen)) { + if(conn->isChief) { + conn->map->mapgen = mapGen; + } + return 0; + } + return -1; } int flib_netconn_send_mapTemplate(flib_netconn *conn, int templateFilter) { - return sendInt(conn, "CFG\nTEMPLATE", templateFilter); + if(!sendInt(conn, "CFG\nTEMPLATE", templateFilter)) { + if(conn->isChief) { + conn->map->templateFilter = templateFilter; + } + return 0; + } + return -1; } int flib_netconn_send_mapMazeSize(flib_netconn *conn, int mazeSize) { - return sendInt(conn, "CFG\nMAZE_SIZE", mazeSize); + if(!sendInt(conn, "CFG\nMAZE_SIZE", mazeSize)) { + if(conn->isChief) { + conn->map->mazeSize = mazeSize; + } + return 0; + } + return -1; } int flib_netconn_send_mapSeed(flib_netconn *conn, const char *seed) { - return sendStr(conn, "CFG\nSEED", seed); + if(!sendStr(conn, "CFG\nSEED", seed)) { + if(conn->isChief) { + char *copy = flib_strdupnull(seed); + if(copy) { + free(conn->map->seed); + conn->map->seed = copy; + } + } + return 0; + } + return -1; } int flib_netconn_send_mapTheme(flib_netconn *conn, const char *theme) { - return sendStr(conn, "CFG\nTHEME", theme); + if(!sendStr(conn, "CFG\nTHEME", theme)) { + if(conn->isChief) { + char *copy = flib_strdupnull(theme); + if(copy) { + free(conn->map->theme); + conn->map->theme = copy; + } + } + return 0; + } + return -1; } int flib_netconn_send_mapDrawdata(flib_netconn *conn, const uint8_t *drawData, size_t size) { int result = -1; - if(!conn || (!drawData && size>0) || size>SIZE_MAX/2) { - flib_log_e("invalid parameter in flib_netconn_send_map"); - } else { + if(!log_badparams_if(!conn || (!drawData && size>0) || size>SIZE_MAX/2)) { uLongf zippedSize = compressBound(size); uint8_t *zipped = flib_malloc(zippedSize+4); // 4 extra bytes for header if(zipped) { @@ -265,18 +351,31 @@ } free(zipped); } + + if(!result && conn->isChief) { + uint8_t *copy = flib_bufdupnull(drawData, size); + if(copy) { + free(conn->map->drawData); + conn->map->drawData = copy; + conn->map->drawDataSize = size; + } + } return result; } int flib_netconn_send_script(flib_netconn *conn, const char *scriptName) { - return sendStr(conn, "CFG\nSCRIPT", scriptName); + if(!sendStr(conn, "CFG\nSCRIPT", scriptName)) { + if(conn->isChief) { + netconn_setScript(conn, scriptName); + } + return 0; + } + return -1; } int flib_netconn_send_scheme(flib_netconn *conn, const flib_cfg *scheme) { int result = -1; - if(!conn || !scheme) { - flib_log_e("null parameter in flib_netconn_send_scheme"); - } else { + if(!log_badparams_if(!conn || !scheme)) { flib_vector *vec = flib_vector_create(); if(vec) { bool error = false; @@ -294,11 +393,21 @@ } flib_vector_destroy(vec); } + + if(!result && conn->isChief) { + netconn_setScheme(conn, scheme); + } return result; } int flib_netconn_send_roundfinished(flib_netconn *conn, bool withoutError) { - return sendInt(conn, "ROUNDFINISHED", withoutError ? 1 : 0); + if(!sendInt(conn, "ROUNDFINISHED", withoutError ? 1 : 0)) { + if(conn->netconnState == NETCONN_STATE_INGAME) { + conn->netconnState = NETCONN_STATE_ROOM; + } + return 0; + } + return -1; } int flib_netconn_send_ban(flib_netconn *conn, const char *playerName) { @@ -334,8 +443,7 @@ } int flib_netconn_send_setServerVar(flib_netconn *conn, const char *name, const char *value) { - if(!conn || !name || !value) { - flib_log_e("null parameter trying to send SET_SERVER_VAR command."); + if(log_badparams_if(!conn || !name || !value)) { return -1; } return flib_netbase_sendf(conn->netBase, "%s\n%s\n%s\n\n", "SET_SERVER_VAR", name, value); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netprotocol.c --- a/project_files/frontlib/net/netprotocol.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netprotocol.c Wed Jun 27 18:02:45 2012 +0200 @@ -80,8 +80,8 @@ } // TODO: Test with empty map -uint8_t *flib_netmsg_to_drawnmapdata(size_t *outlen, char *netmsg) { - uint8_t *result = NULL; +int flib_netmsg_to_drawnmapdata(char *netmsg, uint8_t** outbuf, size_t *outlen) { + int result = -1; // First step: base64 decoding char *base64decout = NULL; @@ -90,24 +90,32 @@ if(ok && base64declen>3) { // Second step: unzip with the QCompress header. That header is just a big-endian // uint32 indicating the length of the uncompressed data. + uint8_t *ubyteBuf = (uint8_t*)base64decout; uint32_t unzipLen = - (((uint32_t)base64decout[0])<<24) - + (((uint32_t)base64decout[1])<<16) - + (((uint32_t)base64decout[2])<<8) - + base64decout[3]; - uint8_t *out = flib_malloc(unzipLen); - if(out) { - uLongf actualUnzipLen = unzipLen; - int resultcode = uncompress(out, &actualUnzipLen, (Bytef*)(base64decout+4), base64declen-4); - if(resultcode == Z_OK) { - result = out; - *outlen = actualUnzipLen; - out = NULL; - } else { - flib_log_e("Uncompressing drawn map failed. Code: %i", resultcode); + (((uint32_t)ubyteBuf[0])<<24) + + (((uint32_t)ubyteBuf[1])<<16) + + (((uint32_t)ubyteBuf[2])<<8) + + ubyteBuf[3]; + if(unzipLen==0) { + *outbuf = NULL; + *outlen = 0; + result = 0; + } else { + uint8_t *out = flib_malloc(unzipLen); + if(out) { + uLongf actualUnzipLen = unzipLen; + int resultcode = uncompress(out, &actualUnzipLen, (Bytef*)(base64decout+4), base64declen-4); + if(resultcode == Z_OK) { + *outbuf = out; + *outlen = actualUnzipLen; + out = NULL; + result = 0; + } else { + flib_log_e("Uncompressing drawn map failed. Code: %i", resultcode); + } } + free(out); } - free(out); } else { flib_log_e("base64 decoding of drawn map failed."); } diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/net/netprotocol.h --- a/project_files/frontlib/net/netprotocol.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/net/netprotocol.h Wed Jun 27 18:02:45 2012 +0200 @@ -31,6 +31,6 @@ * is written to the variable pointed to by outlen. * Returns NULL on error. */ -uint8_t *flib_netmsg_to_drawnmapdata(size_t *outlen, char *netmsg); +int flib_netmsg_to_drawnmapdata(char *netmsg, uint8_t **outbuf, size_t *outlen); #endif /* NETPROTOCOL_H_ */ diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/test.c --- a/project_files/frontlib/test.c Mon Jun 25 15:21:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -#include "frontlib.h" -#include "util/logging.h" -#include "util/buffer.h" -#include "util/util.h" -#include "util/list.h" -#include "model/map.h" -#include "model/weapon.h" -#include "model/schemelist.h" -#include "ipc/mapconn.h" -#include "ipc/gameconn.h" -#include "net/netconn.h" - -#include -#include -#include -#include - -// 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>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("This is the seed value", "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(map); - assert(mapConnection); - - // We don't need the map description anymore - flib_map_release(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("metasettings.ini"); - assert(metaconf); - flib_weaponset *weapons = flib_weaponset_create("Defaultweaps"); - flib_schemelist *schemelist = flib_schemelist_from_ini(metaconf, "schemes.ini"); - - flib_gamesetup setup; - setup.gamescheme = flib_schemelist_find(schemelist, "Default"); - setup.map = flib_map_create_maze("asparagus", "Jungle", MAZE_SIZE_MEDIUM_TUNNELS); - 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]->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 = 0xFF0000F0; - setup.teams[1]->hogsInGame = 8; - flib_team_set_weaponset(setup.teams[0], weapons); - flib_team_set_weaponset(setup.teams[1], weapons); - flib_weaponset_release(weapons); - - flib_gameconn *gameconn = flib_gameconn_create("Medo42", &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); - } -} - -void testSave() { - FILE *demofile = fopen("testsave.42.hws", "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_loadgame("Medo42", 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); - } -} - -void handleNetDisconnect(void *context, int reason, const char *message) { - flib_log_i("Disconnected: %s", message); - flib_netconn_destroy(*(flib_netconn**)context); - *(flib_netconn**)context = NULL; -} - -void handleNetConnected(void *context) { - const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context); - flib_log_i("List of rooms:"); - for(int i=0; iroomCount; i++) { - flib_roomlist_room *room = roomlist->rooms[i]; - flib_log_i("%1s %20s %20s %2i %2i %20s %20s %20s", room->inProgress ? "X" : " ", room->name, room->owner, room->playerCount, room->teamCount, room->map, room->scheme, room->weapons); - } -} - -void handleLobbyJoin(void *context, const char *nick) { - flib_log_i("%s joined", nick); -} - -void handleChat(void *context, const char *nick, const char *msg) { - flib_log_i("%s: %s", nick, msg); - if(!memcmp("frontbot ", msg, strlen("frontbot "))) { - const char *command = msg+strlen("frontbot "); - if(!memcmp("quit", command, strlen("quit"))) { - flib_netconn_send_quit(*(flib_netconn**)context, "Yeth Mathter"); - } else if(!memcmp("describe ", command, strlen("describe "))) { - const char *roomname = command+strlen("describe "); - const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context); - flib_roomlist_room *room = flib_roomlist_find((flib_roomlist*)roomlist, roomname); - if(!room) { - flib_netconn_send_chat(*(flib_netconn**)context, "Unknown room."); - } else { - char *text = flib_asprintf( - "%s is a room created by %s, where %i players (%i teams) are %s on %s%s, using the %s scheme and %s weaponset.", - room->name, - room->owner, - room->playerCount, - room->teamCount, - room->inProgress ? "fighting" : "preparing to fight", - room->map[0]=='+' ? "" : "the map ", - !strcmp("+rnd+", room->map) ? "a random map" : - !strcmp("+maze+", room->map) ? "a random maze" : - !strcmp("+drawn+", room->map) ? "a hand-drawn map" : - room->map, - room->scheme, - room->weapons); - if(text) { - flib_netconn_send_chat(*(flib_netconn**)context, text); - } - free(text); - } - } else if(!memcmp("join ", command, strlen("join "))) { - const char *roomname = command+strlen("join "); - flib_netconn_send_joinRoom(*(flib_netconn**)context, roomname); - } else if(!memcmp("ready", command, strlen("ready"))) { - flib_netconn_send_toggleReady(*(flib_netconn**)context); - } - } -} - -static flib_gamesetup gGamesetup = {0}; -static flib_weaponset *gWeaponset = NULL; - -void handleEnterRoom(void *context, bool isChief) { - flib_netconn_send_toggleReady(*(flib_netconn**)context); -} - -void handleMap(void *context, const flib_map *map, int changeType) { - flib_map_release(gGamesetup.map); - gGamesetup.map = flib_map_copy(map); -} - -void handleCfgScheme(void *context, flib_cfg *cfg) { - flib_cfg_release(gGamesetup.gamescheme); - gGamesetup.gamescheme = flib_cfg_retain(cfg); -} - -void handleWeaponset(void *context, flib_weaponset *weaponset) { - flib_weaponset_release(gWeaponset); - gWeaponset = flib_weaponset_retain(weaponset); -} - -void handleScript(void *context, const char *script) { - free(gGamesetup.script); - gGamesetup.script = flib_strdupnull(script); -} - -void handleTeamAdd(void *context, flib_team *team) { - flib_team *teamptr = flib_team_retain(team); - gGamesetup.teams = flib_list_insert(gGamesetup.teams, &gGamesetup.teamCount, sizeof(*gGamesetup.teams), &teamptr, 0); -} - -void handleTeamRemove(void *context, const char *team) { - for(int i=0; iname)) { - flib_team_release(gGamesetup.teams[i]); - gGamesetup.teams = flib_list_delete(gGamesetup.teams, &gGamesetup.teamCount, sizeof(*gGamesetup.teams), i); - } - } -} - -int main(int argc, char *argv[]) { - flib_init(0); - flib_log_setLevel(FLIB_LOGLEVEL_ALL); - - //testMapPreview(); - //testDemo(); - //testSave(); - //testGame(); - - flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini"); - assert(meta); - flib_netconn *conn = flib_netconn_create("frontbot", meta, "140.247.62.101", 46631); - assert(conn); - flib_cfg_meta_release(meta); - - flib_netconn_onConnected(conn, handleNetConnected, &conn); - flib_netconn_onDisconnected(conn, handleNetDisconnect, &conn); - flib_netconn_onLobbyJoin(conn, handleLobbyJoin, &conn); - flib_netconn_onChat(conn, handleChat, &conn); - flib_netconn_onMapChanged(conn, handleMap, conn); - flib_netconn_onEnterRoom(conn, handleEnterRoom, conn); - flib_netconn_onCfgScheme(conn, handleCfgScheme, conn); - flib_netconn_onWeaponsetChanged(conn, handleWeaponset, conn); - flib_netconn_onScriptChanged(conn, handleScript, conn); - flib_netconn_onTeamAdd(conn, handleTeamAdd, conn); - flib_netconn_onTeamRemove(conn, handleTeamRemove, conn); - flib_netconn_onHogCountChanged(conn, handleHogCountChanged, conn); - - while(conn) { - flib_netconn_tick(conn); - } - - flib_quit(); - return 0; -} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/test.c.nocompile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/frontlib/test.c.nocompile Wed Jun 27 18:02:45 2012 +0200 @@ -0,0 +1,319 @@ +#include "frontlib.h" +#include "util/logging.h" +#include "util/buffer.h" +#include "util/util.h" +#include "util/list.h" +#include "model/map.h" +#include "model/weapon.h" +#include "model/schemelist.h" +#include "ipc/mapconn.h" +#include "ipc/gameconn.h" +#include "net/netconn.h" + +#include +#include +#include +#include + +// 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>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("This is the seed value", "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(map); + assert(mapConnection); + + // We don't need the map description anymore + flib_map_release(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("metasettings.ini"); + assert(metaconf); + flib_weaponset *weapons = flib_weaponset_create("Defaultweaps"); + flib_schemelist *schemelist = flib_schemelist_from_ini(metaconf, "schemes.ini"); + + flib_gamesetup setup; + setup.gamescheme = flib_schemelist_find(schemelist, "Default"); + setup.map = flib_map_create_maze("asparagus", "Jungle", MAZE_SIZE_MEDIUM_TUNNELS); + 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]->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 = 0xFF0000F0; + setup.teams[1]->hogsInGame = 8; + flib_team_set_weaponset(setup.teams[0], weapons); + flib_team_set_weaponset(setup.teams[1], weapons); + flib_weaponset_release(weapons); + + flib_gameconn *gameconn = flib_gameconn_create("Medo42", &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); + } +} + +void testSave() { + FILE *demofile = fopen("testsave.42.hws", "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_loadgame("Medo42", 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); + } +} + +void handleNetDisconnect(void *context, int reason, const char *message) { + flib_log_i("Disconnected: %s", message); + flib_netconn_destroy(*(flib_netconn**)context); + *(flib_netconn**)context = NULL; +} + +void handleNetConnected(void *context) { + const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context); + flib_log_i("List of rooms:"); + for(int i=0; iroomCount; i++) { + flib_roomlist_room *room = roomlist->rooms[i]; + flib_log_i("%1s %20s %20s %2i %2i %20s %20s %20s", room->inProgress ? "X" : " ", room->name, room->owner, room->playerCount, room->teamCount, room->map, room->scheme, room->weapons); + } + flib_netconn_send_joinRoom(*(flib_netconn**)context, "frontlib test"); +} + +void handleLobbyJoin(void *context, const char *nick) { + flib_log_i("%s joined", nick); +} + +void handleChat(void *context, const char *nick, const char *msg) { + flib_log_i("%s: %s", nick, msg); + if(!memcmp("frontbot ", msg, strlen("frontbot "))) { + const char *command = msg+strlen("frontbot "); + if(!memcmp("quit", command, strlen("quit"))) { + flib_netconn_send_quit(*(flib_netconn**)context, "Yeth Mathter"); + } else if(!memcmp("describe ", command, strlen("describe "))) { + const char *roomname = command+strlen("describe "); + const flib_roomlist *roomlist = flib_netconn_get_roomlist(*(flib_netconn**)context); + flib_roomlist_room *room = flib_roomlist_find((flib_roomlist*)roomlist, roomname); + if(!room) { + flib_netconn_send_chat(*(flib_netconn**)context, "Unknown room."); + } else { + char *text = flib_asprintf( + "%s is a room created by %s, where %i players (%i teams) are %s on %s%s, using the %s scheme and %s weaponset.", + room->name, + room->owner, + room->playerCount, + room->teamCount, + room->inProgress ? "fighting" : "preparing to fight", + room->map[0]=='+' ? "" : "the map ", + !strcmp("+rnd+", room->map) ? "a random map" : + !strcmp("+maze+", room->map) ? "a random maze" : + !strcmp("+drawn+", room->map) ? "a hand-drawn map" : + room->map, + room->scheme, + room->weapons); + if(text) { + flib_netconn_send_chat(*(flib_netconn**)context, text); + } + free(text); + } + } else if(!memcmp("join ", command, strlen("join "))) { + const char *roomname = command+strlen("join "); + flib_netconn_send_joinRoom(*(flib_netconn**)context, roomname); + } else if(!memcmp("ready", command, strlen("ready"))) { + flib_netconn_send_toggleReady(*(flib_netconn**)context); + } + } +} + +void handleEnterRoom(void *context, bool isChief) { + flib_netconn_send_toggleReady(*(flib_netconn**)context); +} + +flib_gameconn *gameconn = NULL; + +void emFromNetHandler(void *context, const char *em, int size) { + flib_gameconn_send_enginemsg(gameconn, (const uint8_t*)em, size); +} + +void emFromEngineHandler(void *context, const uint8_t *em, int size) { + flib_netconn_send_engineMessage((flib_netconn*)context, em, size); +} + +void handleRunGame(void *context) { + flib_gamesetup *gamesetup = flib_netconn_create_gameSetup((flib_netconn*)context); + if(gamesetup) { + gameconn = flib_gameconn_create("frontbot", gamesetup, true); + flib_gameconn_onEngineMessage(gameconn, emFromEngineHandler, context); + flib_gameconn_onDisconnect(gameconn, onDisconnect, &gameconn); + startEngineGame(flib_gameconn_getport(gameconn)); + } +} + +int main(int argc, char *argv[]) { + flib_init(0); + flib_log_setLevel(FLIB_LOGLEVEL_ALL); + + //testMapPreview(); + //testDemo(); + //testSave(); + //testGame(); + + flib_cfg_meta *meta = flib_cfg_meta_from_ini("metasettings.ini"); + assert(meta); + flib_netconn *conn = flib_netconn_create("frontbot", meta, "140.247.62.101", 46631); + assert(conn); + flib_cfg_meta_release(meta); + + flib_netconn_onConnected(conn, handleNetConnected, &conn); + flib_netconn_onDisconnected(conn, handleNetDisconnect, &conn); + flib_netconn_onLobbyJoin(conn, handleLobbyJoin, &conn); + flib_netconn_onChat(conn, handleChat, &conn); + flib_netconn_onEnterRoom(conn, handleEnterRoom, conn); + flib_netconn_onRunGame(conn, handleRunGame, conn); + flib_netconn_onEngineMessage(conn, emFromNetHandler, NULL); + + while(conn) { + flib_netconn_tick(conn); + if(gameconn) { + flib_gameconn_tick(gameconn); + } + } + + flib_quit(); + return 0; +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/buffer.c --- a/project_files/frontlib/util/buffer.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/buffer.c Wed Jun 27 18:02:45 2012 +0200 @@ -94,29 +94,20 @@ } 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(len > SIZE_MAX-vec->size) { - return 0; + if(!log_badparams_if(!vec || (!data && len>0)) + && !log_oom_if(len > SIZE_MAX-vec->size)) { + size_t oldSize = vec->size; + if(!log_oom_if(flib_vector_resize(vec, vec->size+len))) { + memmove(((uint8_t*)vec->data) + oldSize, data, len); + return 0; + } } - - size_t oldSize = vec->size; - if(flib_vector_resize(vec, vec->size+len)) { - return 0; - } - - memmove(((uint8_t*)vec->data) + oldSize, data, len); - return len; + return -1; } int flib_vector_appendf(flib_vector *vec, const char *fmt, ...) { int result = -1; - if(!vec || !fmt) { - flib_log_e("null parameter in flib_vector_appendf"); - } else { + if(!log_badparams_if(!vec || !fmt)) { va_list argp; va_start(argp, fmt); char *formatted = flib_vasprintf(fmt, argp); @@ -125,9 +116,7 @@ if(formatted) { size_t len = strlen(formatted); - if(flib_vector_append(vec, formatted, len) == len) { - result = 0; - } + result = flib_vector_append(vec, formatted, len); } } return result; diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/buffer.h --- a/project_files/frontlib/util/buffer.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/buffer.h Wed Jun 27 18:02:45 2012 +0200 @@ -48,8 +48,8 @@ /** * 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 appending fails. + * Returns 0 on success. */ int flib_vector_append(flib_vector *vec, const void *data, size_t len); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/list.c --- a/project_files/frontlib/util/list.c Mon Jun 25 15:21:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -#include "list.h" - -#include -#include "util.h" -#include "logging.h" - -void *flib_list_insert(void *list, int *listSizePtr, size_t elementSize, void *elementPtr, int pos) { - void *result = NULL; - if(!listSizePtr || !elementPtr || pos < 0 || pos > *listSizePtr) { - flib_log_e("Invalid parameter in flib_list_insert"); - } else { - unsigned char *newList = flib_realloc(list, ((*listSizePtr)+1)*elementSize); - if(newList) { - memmove(newList + (pos+1)*elementSize, newList + pos*elementSize, ((*listSizePtr)-pos)*elementSize); - memmove(newList + pos*elementSize, elementPtr, elementSize); - (*listSizePtr)++; - result = newList; - } - } - return result; -} - -void *flib_list_delete(void *list, int *listSizePtr, size_t elementSize, int pos) { - void *result = NULL; - if(!listSizePtr || pos < 0 || pos >= *listSizePtr) { - flib_log_e("Invalid parameter in flib_list_delete"); - } else { - unsigned char *charList = list; - memmove(charList + (pos*elementSize), charList + (pos+1)*elementSize, (*listSizePtr-(pos+1))*elementSize); - (*listSizePtr)--; - - // If the realloc fails, just keep using the old buffer... - size_t newCharSize = (*listSizePtr)*elementSize; - void *newList = flib_realloc(list, newCharSize); - if(newList || newCharSize==0) { - result = newList; - } else { - result = list; - } - } - return result; -} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/list.h --- a/project_files/frontlib/util/list.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/list.h Wed Jun 27 18:02:45 2012 +0200 @@ -6,19 +6,60 @@ #define LIST_H_ #include +#include +#include +#include "util.h" +#include "logging.h" /** - * Insert element into the list and increase listSize. - * Returns a pointer to the modified list on success, NULL on failure. On success, the old - * pointer is no longer valid, and on failure the list remains unchanged (similar to realloc) + * Generate a static function that inserts a new value into a heap array of the given type, + * using realloc and memmove to increase the capacity and shift existing values. + * The function takes a pointer to the array variable and a pointer to the size variable + * because both can be changed by this operation (realloc / increment). + * The function returns 0 on success and leaves the array unchanged on error. */ -void *flib_list_insert(void *list, int *listSizePtr, size_t elementSize, void *elementPtr, int pos); +#define GENERATE_STATIC_LIST_INSERT(fname, type) \ + static int fname(type **listptr, int *listSizePtr, type element, int pos) { \ + int result = -1; \ + if(!listptr || !listSizePtr || pos < 0 || pos > *listSizePtr) { \ + flib_log_e("Invalid parameter in "#fname); \ + } else { \ + type *newList = flib_realloc(*listptr, ((*listSizePtr)+1)*sizeof(type)); \ + if(newList) { \ + memmove(newList + (pos+1), newList + pos, ((*listSizePtr)-pos)*sizeof(type)); \ + newList[pos] = element; \ + (*listSizePtr)++; \ + *listptr = newList; \ + result = 0; \ + } \ + } \ + return result; \ + } /** - * Remove an element from the list and decrease listSize. - * Returns a pointer to the modified list on success, NULL on failure. On success, the old - * pointer is no longer valid, and on failure the list remains unchanged (similar to realloc) + * Generate a static function that deletes a value from a heap array of the given type, + * using realloc and memmove to decrease the capacity and shift existing values. + * The function takes a pointer to the array variable and a pointer to the size variable + * because both can be changed by this operation (realloc / decrement). + * The function returns 0 on success and leaves the array unchanged on error. */ -void *flib_list_delete(void *list, int *listSizePtr, size_t elementSize, int pos); +#define GENERATE_STATIC_LIST_DELETE(fname, type) \ + static int fname(type **listPtr, int *listSizePtr, int pos) { \ + int result = -1; \ + if(!listPtr || !listSizePtr || pos < 0 || pos >= *listSizePtr) { \ + flib_log_e("Invalid parameter in "#fname); \ + } else { \ + memmove((*listPtr) + pos, (*listPtr) + (pos+1), ((*listSizePtr)-(pos+1))*sizeof(type)); \ + (*listSizePtr)--; \ + \ + size_t newCharSize = (*listSizePtr)*sizeof(type); \ + type *newList = flib_realloc((*listPtr), newCharSize); \ + if(newList || newCharSize==0) { \ + (*listPtr) = newList; \ + } /* If the realloc fails, just keep using the old buffer...*/ \ + result = 0; \ + } \ + return result; \ + } #endif /* LIST_H_ */ diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/logging.c --- a/project_files/frontlib/util/logging.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/logging.c Wed Jun 27 18:02:45 2012 +0200 @@ -34,44 +34,47 @@ fprintf(flib_log_getfile(), "%s", buffer); } -static void flib_vflog(const char *prefix, int level, const char *fmt, va_list args) { +static const char *getPrefix(int level) { + switch(level) { + case FLIB_LOGLEVEL_ERROR: return "E"; + case FLIB_LOGLEVEL_WARNING: return "W"; + case FLIB_LOGLEVEL_INFO: return "I"; + case FLIB_LOGLEVEL_DEBUG: return "D"; + default: return "?"; + } +} + +static void _flib_vflog(const char *func, int level, const char *fmt, va_list args) { FILE *logfile = flib_log_getfile(); if(level >= flib_loglevel) { - fprintf(logfile, "%s ", prefix); + fprintf(logfile, "%s ", getPrefix(level)); log_time(logfile); - fprintf(logfile, " ", prefix); + fprintf(logfile, " [%-30s] ", func); vfprintf(logfile, fmt, args); fprintf(logfile, "\n"); fflush(logfile); } } -void flib_log_e(const char *fmt, ...) { +void _flib_flog(const char *func, int level, const char *fmt, ...) { va_list argp; va_start(argp, fmt); - flib_vflog("E", FLIB_LOGLEVEL_ERROR, fmt, argp); + _flib_vflog(func, level, fmt, argp); va_end(argp); } -void flib_log_w(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog("W", FLIB_LOGLEVEL_WARNING, fmt, argp); - va_end(argp); +bool _flib_fassert(const char *func, int level, bool cond, const char *fmt, ...) { + if(!cond) { + va_list argp; + va_start(argp, fmt); + _flib_vflog(func, level, fmt, argp); + va_end(argp); + } + return !cond; } -void flib_log_i(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog("I", FLIB_LOGLEVEL_INFO, fmt, argp); - va_end(argp); -} - -void flib_log_d(const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - flib_vflog("D", FLIB_LOGLEVEL_DEBUG, fmt, argp); - va_end(argp); +bool _flib_assert_params(const char *func, bool cond) { + return _flib_fassert(func, FLIB_LOGLEVEL_ERROR, cond, "Invalid parameter to function"); } int flib_log_getLevel() { diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/logging.h --- a/project_files/frontlib/util/logging.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/logging.h Wed Jun 27 18:02:45 2012 +0200 @@ -17,10 +17,27 @@ */ 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, ...); -void flib_log_d(const char *fmt, ...); +/** + * Evaluates the expression cond. If it is true, a formatted error will be logged. + * Returns true if an error is logged, false otherwise (i.e. the boolean value of the argument) + */ +#define log_e_if(cond, ...) _flib_fassert(__func__, FLIB_LOGLEVEL_ERROR, !(bool)(cond), __VA_ARGS__) +#define log_w_if(cond, ...) _flib_fassert(__func__, FLIB_LOGLEVEL_WARNING, !(bool)(cond), __VA_ARGS__) + +/** + * Shorthand for some common error types + */ +#define log_badparams_if(cond) log_e_if(cond, "Invalid Parameters") +#define log_oom_if(cond) log_e_if(cond, "Out of Memory") + +#define flib_log_e(...) _flib_flog(__func__, FLIB_LOGLEVEL_ERROR, __VA_ARGS__) +#define flib_log_w(...) _flib_flog(__func__, FLIB_LOGLEVEL_WARNING, __VA_ARGS__) +#define flib_log_i(...) _flib_flog(__func__, FLIB_LOGLEVEL_INFO, __VA_ARGS__) +#define flib_log_d(...) _flib_flog(__func__, FLIB_LOGLEVEL_DEBUG, __VA_ARGS__) + +bool _flib_assert_params(const char *func, bool cond); +bool _flib_fassert(const char *func, int level, bool cond, const char *fmt, ...); +void _flib_flog(const char *func, int level, const char *fmt, ...); int flib_log_getLevel(); void flib_log_setLevel(int level); diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/util.c --- a/project_files/frontlib/util/util.c Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/util.c Wed Jun 27 18:02:45 2012 +0200 @@ -162,3 +162,27 @@ char *shrunk = realloc(outbuf, outpos+1); return shrunk ? shrunk : outbuf; } + +bool flib_contains_dir_separator(const char *str) { + if(!log_badparams_if(!str)) { + for(;*str;str++) { + if(*str=='\\' || *str=='/') { + return true; + } + } + } + return false; +} + +int flib_gets(char *str, size_t strlen) { + if(fgets(str, strlen, stdin)) { + for(char *s=str; *s; s++) { + if(*s=='\r' || *s=='\n') { + *s = 0; + break; + } + } + return 0; + } + return -1; +} diff -r 8eed495fd8da -r 15f722e0b96f project_files/frontlib/util/util.h --- a/project_files/frontlib/util/util.h Mon Jun 25 15:21:18 2012 +0200 +++ b/project_files/frontlib/util/util.h Wed Jun 27 18:02:45 2012 +0200 @@ -87,4 +87,12 @@ */ char *flib_urldecode(const char *str); +/** + * Figure out if the string contains / or \. Useful in routines that + * construct filenames. + */ +bool flib_contains_dir_separator(const char *str); + +int flib_gets(char *str, size_t strlen); + #endif