diff -r 5b0aeef8ba2a -r 5608ac657362 project_files/frontlib/net/netconn.c --- a/project_files/frontlib/net/netconn.c Thu Jun 21 21:32:12 2012 +0200 +++ b/project_files/frontlib/net/netconn.c Mon Jun 25 00:42:07 2012 +0200 @@ -18,93 +18,21 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#include "netconn.h" -#include "netbase.h" +// TODO: Check the state transitions. Document with a diagram or something + +#include "netconn_internal.h" #include "netprotocol.h" #include "../util/logging.h" #include "../util/util.h" #include "../model/roomlist.h" #include "../md5/md5.h" +#include "../base64/base64.h" -#include #include #include #include #include -struct _flib_netconn { - flib_netbase *netBase; - char *playerName; - flib_cfg_meta *metaCfg; - 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 - - - void (*onMessageCb)(void *context, int msgtype, const char *msg); - void *onMessageCtx; - - void (*onConnectedCb)(void *context); - void *onConnectedCtx; - - void (*onDisconnectedCb)(void *context, int reason, const char *message); - void *onDisconnectedCtx; - - void (*onRoomAddCb)(void *context, const flib_roomlist_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 *onRoomUpdateCtx; - - void (*onChatCb)(void *context, const char *nick, const char *msg); - void *onChatCtx; - - void (*onLobbyJoinCb)(void *context, const char *nick); - void *onLobbyJoinCtx; - - void (*onLobbyLeaveCb)(void *context, const char *nick, const char *partMessage); - void *onLobbyLeaveCtx; - - void (*onRoomJoinCb)(void *context, const char *nick); - void *onRoomJoinCtx; - - void (*onRoomLeaveCb)(void *context, const char *nick, const char *partMessage); - void *onRoomLeaveCtx; - - void (*onNickTakenCb)(void *context, const char *nick); - void *onNickTakenCtx; - - void (*onNickAcceptCb)(void *context, const char *nick); - void *onNickAcceptCtx; - - void (*onPasswordRequestCb)(void *context, const char *nick); - void *onPasswordRequestCtx; - - void (*onRoomChiefStatusCb)(void *context, bool isChief); - void *onRoomChiefStatusCtx; - - void (*onReadyStateCb)(void *context, const char *nick, bool ready); - void *onReadyStateCtx; - - void (*onEnterRoomCb)(void *context, bool chief); - void *onEnterRoomCtx; - - void (*onLeaveRoomCb)(void *context, int reason, const char *message); - void *onLeaveRoomCtx; - - void (*onTeamAddCb)(void *context, flib_team *team); - void *onTeamAddCtx; - - bool running; - bool destroyRequested; -}; - static void defaultCallback_onMessage(void *context, int msgtype, const char *msg) { flib_log_i("Net: [%i] %s", msgtype, msg); } @@ -115,6 +43,7 @@ static void defaultCallback_int_str(void *context, int i, const char *str) {} static void defaultCallback_str_str(void *context, const char *str1, const char *str2) {} static void defaultCallback_str_bool(void *context, const char *str, bool b) {} +static void defaultCallback_str_int(void *context, const char *str, int i) {} static void defaultCallback_onRoomAdd(void *context, const flib_roomlist_room *room) {} static void defaultCallback_onRoomUpdate(void *context, const char *oldName, const flib_roomlist_room *room) {} @@ -149,6 +78,10 @@ } static void defaultCallback_onTeamAdd(void *context, flib_team *team) {} +static void defaultCallback_onTeamColorChanged(void *context, const char *teamName, uint32_t color) {} +static void defaultCallback_onCfgScheme(void *context, flib_cfg *scheme) {} +static void defaultCallback_onMapChanged(void *context, const flib_map *map, int changetype) {} +static void defaultCallback_onWeaponsetChanged(void *context, flib_weaponset *weaponset) {} static void clearCallbacks(flib_netconn *conn) { flib_netconn_onMessage(conn, NULL, NULL); @@ -163,12 +96,24 @@ flib_netconn_onRoomJoin(conn, NULL, NULL); flib_netconn_onRoomLeave(conn, NULL, NULL); flib_netconn_onNickTaken(conn, NULL, NULL); - flib_netconn_onNickAccept(conn, NULL, NULL); flib_netconn_onPasswordRequest(conn, NULL, NULL); flib_netconn_onRoomChiefStatus(conn, NULL, NULL); - flib_netconn_onReadyStateCb(conn, NULL, NULL); - flib_netconn_onEnterRoomCb(conn, NULL, NULL); - flib_netconn_onTeamAddCb(conn, NULL, NULL); + flib_netconn_onReadyState(conn, NULL, NULL); + flib_netconn_onEnterRoom(conn, NULL, NULL); + flib_netconn_onLeaveRoom(conn, NULL, NULL); + flib_netconn_onTeamAdd(conn, NULL, NULL); + flib_netconn_onTeamDelete(conn, NULL, NULL); + flib_netconn_onRunGame(conn, NULL, NULL); + flib_netconn_onTeamAccepted(conn, NULL, NULL); + flib_netconn_onHogCountChanged(conn, NULL, NULL); + flib_netconn_onTeamColorChanged(conn, NULL, NULL); + flib_netconn_onEngineMessage(conn, NULL, NULL); + flib_netconn_onCfgScheme(conn, NULL, NULL); + flib_netconn_onMapChanged(conn, NULL, NULL); + flib_netconn_onScriptChanged(conn, NULL, NULL); + flib_netconn_onWeaponsetChanged(conn, NULL, NULL); + flib_netconn_onAdminAccess(conn, NULL, NULL); + flib_netconn_onServerVar(conn, NULL, NULL); } flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port) { @@ -183,6 +128,7 @@ newConn->isChief = false; newConn->metaCfg = flib_cfg_meta_retain(metacfg); newConn->roomList = flib_roomlist_create(); + newConn->map = flib_map_create_named("", "NoSuchMap"); newConn->running = false; newConn->destroyRequested = false; clearCallbacks(newConn); @@ -212,6 +158,7 @@ flib_netbase_destroy(conn->netBase); flib_cfg_meta_release(conn->metaCfg); flib_roomlist_destroy(conn->roomList); + flib_map_release(conn->map); free(conn->playerName); free(conn); } @@ -238,65 +185,6 @@ return result; } -int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) { - int result = -1; - if(!conn) { - flib_log_e("null parameter in flib_netconn_send_quit"); - } else { - result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "QUIT", quitmsg ? quitmsg : "User quit"); - } - return result; -} - -int flib_netconn_send_chat(flib_netconn *conn, const char *chat) { - int result = -1; - if(!conn || !chat) { - flib_log_e("null parameter in flib_netconn_send_chat"); - } else { - result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "CHAT", chat); - } - return result; -} - -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 { - char *tmpName = flib_strdupnull(nick); - if(tmpName) { - if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) { - free(conn->playerName); - conn->playerName = tmpName; - tmpName = NULL; - result = 0; - } - } - free(tmpName); - } - return result; -} - -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 { - md5_state_t md5state; - uint8_t md5bytes[16]; - char md5hex[33]; - md5_init(&md5state); - md5_append(&md5state, (unsigned char*)latin1Passwd, strlen(latin1Passwd)); - md5_finish(&md5state, md5bytes); - for(int i=0;inetBase, "%s\n%s\n\n", "PASSWORD", md5hex); - } - return result; -} - /* * Callback registration functions */ @@ -412,15 +300,6 @@ } } -void flib_netconn_onNickAccept(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { - if(!conn) { - flib_log_e("null parameter in flib_netconn_onNickAccept"); - } else { - conn->onNickAcceptCb = callback ? callback : &defaultCallback_str; - conn->onNickAcceptCtx = context; - } -} - void flib_netconn_onPasswordRequest(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { if(!conn) { flib_log_e("null parameter in flib_netconn_onPasswordRequest"); @@ -442,42 +321,162 @@ } } -void flib_netconn_onReadyStateCb(flib_netconn *conn, void (*callback)(void *context, const char *nick, bool ready), void* context) { +void flib_netconn_onReadyState(flib_netconn *conn, void (*callback)(void *context, const char *nick, bool ready), void* context) { if(!conn) { - flib_log_e("null parameter in flib_netconn_onReadyStateCb"); + flib_log_e("null parameter in flib_netconn_onReadyState"); } else { conn->onReadyStateCb = callback ? callback : &defaultCallback_str_bool; conn->onReadyStateCtx = context; } } -void flib_netconn_onEnterRoomCb(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context) { +void flib_netconn_onEnterRoom(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context) { if(!conn) { - flib_log_e("null parameter in flib_netconn_onEnterRoomCb"); + flib_log_e("null parameter in flib_netconn_onEnterRoom"); } else { conn->onEnterRoomCb = callback ? callback : &defaultCallback_bool; conn->onEnterRoomCtx = context; } } -void flib_netconn_onLeaveRoomCb(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context) { +void flib_netconn_onLeaveRoom(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context) { if(!conn) { - flib_log_e("null parameter in flib_netconn_onLeaveRoomCb"); + flib_log_e("null parameter in flib_netconn_onLeaveRoom"); } else { conn->onLeaveRoomCb = callback ? callback : &defaultCallback_int_str; conn->onLeaveRoomCtx = context; } } -void flib_netconn_onTeamAddCb(flib_netconn *conn, void (*callback)(void *context, flib_team *team), void *context) { +void flib_netconn_onTeamAdd(flib_netconn *conn, void (*callback)(void *context, flib_team *team), void *context) { if(!conn) { - flib_log_e("null parameter in flib_netconn_onTeamAddCb"); + flib_log_e("null parameter in flib_netconn_onTeamAdd"); } else { conn->onTeamAddCb = callback ? callback : &defaultCallback_onTeamAdd; conn->onTeamAddCtx = context; } } +void flib_netconn_onTeamDelete(flib_netconn *conn, void (*callback)(void *context, const char *teamname), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onTeamDelete"); + } else { + conn->onTeamDeleteCb = callback ? callback : &defaultCallback_str; + conn->onTeamDeleteCtx = context; + } +} + +void flib_netconn_onRunGame(flib_netconn *conn, void (*callback)(void *context), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onRunGame"); + } else { + conn->onRunGameCb = callback ? callback : &defaultCallback_void; + conn->onRunGameCtx = context; + } +} + +void flib_netconn_onTeamAccepted(flib_netconn *conn, void (*callback)(void *context, const char *teamName), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onTeamAccepted"); + } else { + conn->onTeamAcceptedCb = callback ? callback : &defaultCallback_str; + conn->onTeamAcceptedCtx = context; + } +} + +void flib_netconn_onHogCountChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, int hogs), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onHogCountChanged"); + } else { + conn->onHogCountChangedCb = callback ? callback : &defaultCallback_str_int; + conn->onHogCountChangedCtx = context; + } +} + +void flib_netconn_onTeamColorChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, uint32_t colorARGB), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onTeamColorChanged"); + } else { + conn->onTeamColorChangedCb = callback ? callback : &defaultCallback_onTeamColorChanged; + conn->onTeamColorChangedCtx = context; + } +} + +void flib_netconn_onEngineMessage(flib_netconn *conn, void (*callback)(void *context, const char *message, int size), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onEngineMessage"); + } else { + conn->onEngineMessageCb = callback ? callback : &defaultCallback_str_int; + conn->onEngineMessageCtx = context; + } +} + +void flib_netconn_onCfgScheme(flib_netconn *conn, void (*callback)(void *context, flib_cfg *scheme), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onCfgScheme"); + } else { + conn->onCfgSchemeCb = callback ? callback : &defaultCallback_onCfgScheme; + conn->onCfgSchemeCtx = context; + } +} + +void flib_netconn_onMapChanged(flib_netconn *conn, void (*callback)(void *context, const flib_map *map, int changetype), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onMapChanged"); + } else { + conn->onMapChangedCb = callback ? callback : &defaultCallback_onMapChanged; + conn->onMapChangedCtx = context; + } +} + +void flib_netconn_onScriptChanged(flib_netconn *conn, void (*callback)(void *context, const char *script), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onScriptChanged"); + } else { + conn->onScriptChangedCb = callback ? callback : &defaultCallback_str; + conn->onScriptChangedCtx = context; + } +} + +void flib_netconn_onWeaponsetChanged(flib_netconn *conn, void (*callback)(void *context, flib_weaponset *weaponset), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onWeaponsetChanged"); + } else { + conn->onWeaponsetChangedCb = callback ? callback : &defaultCallback_onWeaponsetChanged; + conn->onWeaponsetChangedCtx = context; + } +} + +void flib_netconn_onAdminAccess(flib_netconn *conn, void (*callback)(void *context), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onAdminAccess"); + } else { + conn->onAdminAccessCb = callback ? callback : &defaultCallback_void; + conn->onAdminAccessCtx = context; + } +} + +void flib_netconn_onServerVar(flib_netconn *conn, void (*callback)(void *context, const char *name, const char *value), void *context) { + if(!conn) { + flib_log_e("null parameter in flib_netconn_onServerVar"); + } else { + conn->onServerVarCb = callback ? callback : &defaultCallback_str_str; + conn->onServerVarCtx = context; + } +} + +void 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 = map; + } else { + flib_log_e("Error resetting netconn.map"); + } +} + static void flib_netconn_wrappedtick(flib_netconn *conn) { flib_netmsg *netmsg; flib_netbase *net = conn->netBase; @@ -503,14 +502,14 @@ if(netmsg->partCount<2) { flib_log_w("Net: Malformed NICK message"); } else { - free(conn->playerName); - conn->playerName = flib_strdupnull(netmsg->parts[1]); - if(!conn->playerName) { + char *nick = flib_strdupnull(netmsg->parts[1]); + if(nick) { + free(conn->playerName); + conn->playerName = nick; + } else { conn->netconnState = NETCONN_STATE_DISCONNECTED; conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Out of memory"); exit = true; - } else { - conn->onNickAcceptCb(conn->onNickAcceptCtx, conn->playerName); } } } else if (!strcmp(cmd, "PROTO")) { @@ -583,18 +582,9 @@ free(joined); } } else if(!strcmp(cmd, "SERVER_VARS")) { - // TODO -// QStringList tmp = lst; -// tmp.removeFirst(); -// while (tmp.size() >= 2) -// { -// if(tmp[0] == "MOTD_NEW") emit serverMessageNew(tmp[1]); -// else if(tmp[0] == "MOTD_OLD") emit serverMessageOld(tmp[1]); -// else if(tmp[0] == "LATEST_PROTO") emit latestProtocolVar(tmp[1].toInt()); -// -// tmp.removeFirst(); -// tmp.removeFirst(); -// } + for(int offset=1; offset+2partCount; offset+=2) { + conn->onServerVarCb(conn->onServerVarCtx, netmsg->parts[offset], netmsg->parts[offset+1]); + } } else if (!strcmp(cmd, "CLIENT_FLAGS")) { if(netmsg->partCount < 3 || strlen(netmsg->parts[1]) < 2) { flib_log_w("Net: Malformed CLIENT_FLAGS message"); @@ -606,12 +596,6 @@ switch(flags[i]) { case 'r': for(int j = 2; j < netmsg->partCount; ++j) { - if (!strcmp(conn->playerName, netmsg->parts[i])) { - // TODO what is the reason behind this (copied from QtFrontend)? - if (conn->isChief && !setFlag) { - flib_netbase_sendf(conn->netBase, "%s\n\n", "TOGGLE_READY"); - } - } conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[i], setFlag); } break; @@ -631,21 +615,22 @@ conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error"); exit = true; } else { + team->remoteDriven = true; conn->onTeamAddCb(conn->onTeamAddCtx, team); } + flib_team_release(team); } } else if (!strcmp(cmd, "REMOVE_TEAM")) { if(netmsg->partCount != 2) { flib_log_w("Net: Bad REMOVETEAM message"); } else { - // TODO - // emit RemoveNetTeam(HWTeam(lst[1])); + conn->onTeamDeleteCb(conn->onTeamDeleteCtx, netmsg->parts[1]); } } else if(!strcmp(cmd, "ROOMABANDONED")) { - conn->netconnState = NETCONN_STATE_LOBBY; + leaveRoom(conn); conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed"); } else if(!strcmp(cmd, "KICKED")) { - conn->netconnState = NETCONN_STATE_LOBBY; + leaveRoom(conn); conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked"); } else if(!strcmp(cmd, "JOINED")) { if(netmsg->partCount < 2) { @@ -718,8 +703,7 @@ } } else if (!strcmp(cmd, "RUN_GAME")) { conn->netconnState = NETCONN_STATE_INGAME; - // TODO - // emit AskForRunGame(); + conn->onRunGameCb(conn->onRunGameCtx); } else if (!strcmp(cmd, "ASKPASSWORD")) { conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName); } else if (!strcmp(cmd, "NOTICE")) { @@ -740,49 +724,128 @@ if (netmsg->partCount != 2) { flib_log_w("Net: Bad TEAM_ACCEPTED message"); } else { - // TODO - // emit TeamAccepted(lst[1]); + conn->onTeamAcceptedCb(conn->onTeamAcceptedCtx, netmsg->parts[1]); } } else if (!strcmp(cmd, "CFG")) { if(netmsg->partCount < 3) { flib_log_w("Net: Bad CFG message"); } else { - // TODO -// QStringList tmp = lst; -// tmp.removeFirst(); -// tmp.removeFirst(); -// if (lst[1] == "SCHEME") -// emit netSchemeConfig(tmp); -// else -// emit paramChanged(lst[1], tmp); + 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) { + conn->onCfgSchemeCb(conn->onCfgSchemeCtx, cfg); + } else { + flib_log_e("Error processing CFG SCHEME message"); + } + flib_cfg_release(cfg); + } 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; + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_FULL); + } else { + flib_log_e("Error processing CFG FULLMAPCONFIG message"); + } + } else if(!strcmp(subcmd, "MAP") && netmsg->partCount == 3) { + char *mapname = flib_strdupnull(netmsg->parts[2]); + if(mapname) { + free(conn->map->name); + conn->map->name = mapname; + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAP); + } else { + flib_log_e("Error processing CFG MAP message"); + } + } else if(!strcmp(subcmd, "THEME") && netmsg->partCount == 3) { + char *themename = flib_strdupnull(netmsg->parts[2]); + if(themename) { + free(conn->map->theme); + conn->map->theme = themename; + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_THEME); + } else { + flib_log_e("Error processing CFG THEME message"); + } + } else if(!strcmp(subcmd, "SEED") && netmsg->partCount == 3) { + char *seed = flib_strdupnull(netmsg->parts[2]); + if(seed) { + free(conn->map->seed); + conn->map->seed = seed; + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_SEED); + } else { + flib_log_e("Error processing CFG SEED message"); + } + } else if(!strcmp(subcmd, "TEMPLATE") && netmsg->partCount == 3) { + conn->map->templateFilter = atoi(netmsg->parts[2]); + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_TEMPLATE); + } else if(!strcmp(subcmd, "MAPGEN") && netmsg->partCount == 3) { + conn->map->mapgen = atoi(netmsg->parts[2]); + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAPGEN); + } else if(!strcmp(subcmd, "MAZE_SIZE") && netmsg->partCount == 3) { + conn->map->mazeSize = atoi(netmsg->parts[2]); + 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) { + free(conn->map->drawData); + conn->map->drawData = drawnMapData; + conn->map->drawDataSize = drawnMapSize; + conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_DRAWNMAP); + } else { + flib_log_e("Error processing CFG DRAWNMAP message"); + } + } else if(!strcmp(subcmd, "SCRIPT") && netmsg->partCount == 3) { + 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) { + conn->onWeaponsetChangedCb(conn->onWeaponsetChangedCtx, weapons); + } else { + flib_log_e("Error processing CFG AMMO message"); + } + flib_weaponset_release(weapons); + } else { + flib_log_w("Net: Unknown or malformed CFG subcommand: %s", subcmd); + } } } else if (!strcmp(cmd, "HH_NUM")) { if (netmsg->partCount != 3) { - flib_log_w("Net: Bad TEAM_ACCEPTED message"); + flib_log_w("Net: Bad HH_NUM message"); } else { - // TODO -// HWTeam tmptm(lst[1]); -// tmptm.setNumHedgehogs(lst[2].toUInt()); -// emit hhnumChanged(tmptm); + 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 { + conn->onHogCountChangedCb(conn->onHogCountChangedCtx, netmsg->parts[1], hogs); + } } } else if (!strcmp(cmd, "TEAM_COLOR")) { if (netmsg->partCount != 3) { flib_log_w("Net: Bad TEAM_COLOR message"); } else { - // TODO -// HWTeam tmptm(lst[1]); -// tmptm.setColor(lst[2].toInt()); -// emit teamColorChanged(tmptm); + long color; + if(sscanf(netmsg->parts[2], "#%lx", &color)) { + conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], (uint32_t)color); + } else { + flib_log_w("Net: Bad TEAM_COLOR message: Color %s", netmsg->parts[2]); + } } } else if (!strcmp(cmd, "EM")) { if(netmsg->partCount < 2) { flib_log_w("Net: Bad EM message"); } else { - // TODO -// for(int i = 1; i < netmsg->partCount; ++i) { -// QByteArray em = QByteArray::fromBase64(lst[i].toAscii()); -// emit FromNet(em); -// } + for(int i = 1; i < netmsg->partCount; ++i) { + char *out = NULL; + 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); + } else { + flib_log_e("Net: Malformed engine message: %s", netmsg->parts[i]); + } + free(out); + } } } else if (!strcmp(cmd, "BYE")) { if (netmsg->partCount < 2) { @@ -797,7 +860,7 @@ exit = true; } } else if (!strcmp(cmd, "ADMIN_ACCESS")) { - // TODO callback? + conn->onAdminAccessCb(conn->onAdminAccessCtx); conn->isAdmin = true; } else if (!strcmp(cmd, "ROOM_CONTROL_ACCESS")) { if (netmsg->partCount < 2) {