project_files/frontlib/net/netconn.c
changeset 7275 15f722e0b96f
parent 7273 8eed495fd8da
child 7314 6171f0bad318
equal deleted inserted replaced
7273:8eed495fd8da 7275:15f722e0b96f
    25 #include "../util/logging.h"
    25 #include "../util/logging.h"
    26 #include "../util/util.h"
    26 #include "../util/util.h"
    27 #include "../model/roomlist.h"
    27 #include "../model/roomlist.h"
    28 #include "../md5/md5.h"
    28 #include "../md5/md5.h"
    29 #include "../base64/base64.h"
    29 #include "../base64/base64.h"
       
    30 #include "../model/mapcfg.h"
    30 
    31 
    31 #include <stdlib.h>
    32 #include <stdlib.h>
    32 #include <string.h>
    33 #include <string.h>
    33 #include <errno.h>
    34 #include <errno.h>
    34 #include <ctype.h>
    35 #include <ctype.h>
    35 
    36 
    36 flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port) {
    37 flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *dataDirPath, const char *host, uint16_t port) {
    37 	flib_netconn *result = NULL;
    38 	flib_netconn *result = NULL;
    38 	if(!playerName || !metacfg || !host) {
    39 	if(!playerName || !metacfg || !host) {
    39 		flib_log_e("null parameter in flib_netconn_create");
    40 		flib_log_e("null parameter in flib_netconn_create");
    40 	} else {
    41 	} else {
    41 		flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
    42 		flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
    42 		if(newConn) {
    43 		if(newConn) {
       
    44 			newConn->netBase = flib_netbase_create(host, port);
       
    45 			newConn->playerName = flib_strdupnull(playerName);
       
    46 			newConn->dataDirPath = flib_strdupnull(dataDirPath);
       
    47 
    43 			newConn->netconnState = NETCONN_STATE_CONNECTING;
    48 			newConn->netconnState = NETCONN_STATE_CONNECTING;
    44 			newConn->isAdmin = false;
    49 			newConn->isAdmin = false;
       
    50 			newConn->metaCfg = flib_cfg_meta_retain(metacfg);
       
    51 			newConn->roomList.roomCount = 0;
       
    52 			newConn->roomList.rooms = NULL;
       
    53 
    45 			newConn->isChief = false;
    54 			newConn->isChief = false;
    46 			newConn->metaCfg = flib_cfg_meta_retain(metacfg);
       
    47 			newConn->roomList = flib_roomlist_create();
       
    48 			newConn->map = flib_map_create_named("", "NoSuchMap");
    55 			newConn->map = flib_map_create_named("", "NoSuchMap");
       
    56 			newConn->pendingTeamlist.teamCount = 0;
       
    57 			newConn->pendingTeamlist.teams = NULL;
       
    58 			newConn->teamlist.teamCount = 0;
       
    59 			newConn->teamlist.teams = NULL;
       
    60 			newConn->scheme = NULL;
       
    61 			newConn->script = NULL;
       
    62 			newConn->weaponset = NULL;
       
    63 
    49 			newConn->running = false;
    64 			newConn->running = false;
    50 			newConn->destroyRequested = false;
    65 			newConn->destroyRequested = false;
    51 			clearCallbacks(newConn);
    66 			netconn_clearCallbacks(newConn);
    52 			newConn->netBase = flib_netbase_create(host, port);
    67 			if(newConn->netBase && newConn->playerName && newConn->dataDirPath && newConn->map) {
    53 			newConn->playerName = flib_strdupnull(playerName);
       
    54 			if(newConn->netBase && newConn->playerName && newConn->roomList) {
       
    55 				result = newConn;
    68 				result = newConn;
    56 				newConn = NULL;
    69 				newConn = NULL;
    57 			}
    70 			}
    58 		}
    71 		}
    59 		flib_netconn_destroy(newConn);
    72 		flib_netconn_destroy(newConn);
    67 			/*
    80 			/*
    68 			 * The function was called from a callback, so the tick function is still running
    81 			 * The function was called from a callback, so the tick function is still running
    69 			 * and we delay the actual destruction. We ensure no further callbacks will be
    82 			 * and we delay the actual destruction. We ensure no further callbacks will be
    70 			 * sent to prevent surprises.
    83 			 * sent to prevent surprises.
    71 			 */
    84 			 */
    72 			clearCallbacks(conn);
    85 			netconn_clearCallbacks(conn);
    73 			conn->destroyRequested = true;
    86 			conn->destroyRequested = true;
    74 		} else {
    87 		} else {
    75 			flib_netbase_destroy(conn->netBase);
    88 			flib_netbase_destroy(conn->netBase);
       
    89 			free(conn->playerName);
       
    90 			free(conn->dataDirPath);
       
    91 
    76 			flib_cfg_meta_release(conn->metaCfg);
    92 			flib_cfg_meta_release(conn->metaCfg);
    77 			flib_roomlist_destroy(conn->roomList);
    93 			flib_roomlist_clear(&conn->roomList);
       
    94 
    78 			flib_map_release(conn->map);
    95 			flib_map_release(conn->map);
    79 			free(conn->playerName);
    96 			flib_teamlist_clear(&conn->pendingTeamlist);
       
    97 			flib_teamlist_clear(&conn->teamlist);
       
    98 			flib_cfg_release(conn->scheme);
       
    99 			free(conn->script);
       
   100 			flib_weaponset_release(conn->weaponset);
       
   101 
    80 			free(conn);
   102 			free(conn);
    81 		}
   103 		}
    82 	}
   104 	}
    83 }
   105 }
    84 
   106 
    85 const flib_roomlist *flib_netconn_get_roomlist(flib_netconn *conn) {
   107 const flib_roomlist *flib_netconn_get_roomlist(flib_netconn *conn) {
    86 	const flib_roomlist *result = NULL;
   108 	const flib_roomlist *result = NULL;
    87 	if(!conn) {
   109 	if(!conn) {
    88 		flib_log_e("null parameter in flib_netconn_get_roomlist");
   110 		flib_log_e("null parameter in flib_netconn_get_roomlist");
    89 	} else {
   111 	} else {
    90 		result = conn->roomList;
   112 		result = &conn->roomList;
    91 	}
   113 	}
    92 	return result;
   114 	return result;
    93 }
   115 }
    94 
   116 
    95 bool flib_netconn_is_chief(flib_netconn *conn) {
   117 bool flib_netconn_is_chief(flib_netconn *conn) {
   100 		result = conn->isChief;
   122 		result = conn->isChief;
   101 	}
   123 	}
   102 	return result;
   124 	return result;
   103 }
   125 }
   104 
   126 
   105 void leaveRoom(flib_netconn *conn) {
   127 void netconn_leaveRoom(flib_netconn *conn) {
   106 	conn->netconnState = NETCONN_STATE_LOBBY;
   128 	conn->netconnState = NETCONN_STATE_LOBBY;
   107 	conn->isChief = false;
   129 	conn->isChief = false;
   108 	flib_map *map = flib_map_create_named("", "NoSuchMap");
   130 	flib_map_release(conn->map);
   109 	if(map) {
   131 	conn->map = flib_map_create_named("", "NoSuchMap");
       
   132 	flib_teamlist_clear(&conn->pendingTeamlist);
       
   133 	flib_teamlist_clear(&conn->teamlist);
       
   134 	flib_cfg_release(conn->scheme);
       
   135 	conn->scheme = NULL;
       
   136 	free(conn->script);
       
   137 	conn->script = NULL;
       
   138 	flib_weaponset_release(conn->weaponset);
       
   139 	conn->weaponset = NULL;
       
   140 }
       
   141 
       
   142 bool flib_netconn_is_in_room_context(flib_netconn *conn) {
       
   143 	return conn && (conn->netconnState == NETCONN_STATE_ROOM || conn->netconnState == NETCONN_STATE_INGAME);
       
   144 }
       
   145 
       
   146 void netconn_setMap(flib_netconn *conn, const flib_map *map) {
       
   147 	flib_map *copy = flib_map_copy(map);
       
   148 	if(copy) {
   110 		flib_map_release(conn->map);
   149 		flib_map_release(conn->map);
   111 		conn->map = map;
   150 		conn->map = copy;
       
   151 	}
       
   152 }
       
   153 
       
   154 void netconn_setWeaponset(flib_netconn *conn, const flib_weaponset *weaponset) {
       
   155 	flib_weaponset *copy = flib_weaponset_copy(weaponset);
       
   156 	if(copy) {
       
   157 		flib_weaponset_release(conn->weaponset);
       
   158 		conn->weaponset = copy;
       
   159 	}
       
   160 }
       
   161 
       
   162 void netconn_setScript(flib_netconn *conn, const char *script) {
       
   163 	char *copy = flib_strdupnull(script);
       
   164 	if(copy) {
       
   165 		free(conn->script);
       
   166 		conn->script = copy;
       
   167 	}
       
   168 }
       
   169 
       
   170 void netconn_setScheme(flib_netconn *conn, const flib_cfg *scheme) {
       
   171 	flib_cfg *copy = flib_cfg_copy(scheme);
       
   172 	if(copy) {
       
   173 		flib_cfg_release(conn->scheme);
       
   174 		conn->scheme = copy;
       
   175 	}
       
   176 }
       
   177 
       
   178 flib_gamesetup *flib_netconn_create_gameSetup(flib_netconn *conn) {
       
   179 	flib_gamesetup *result = NULL;
       
   180 	if(!conn) {
       
   181 		flib_log_e("null parameter in flib_netconn_create_gameSetup");
   112 	} else {
   182 	} else {
   113 		flib_log_e("Error resetting netconn.map");
   183 		if(conn->teamlist.teamCount==0 || !conn->scheme || !conn->weaponset) {
   114 	}
   184 			flib_log_e("Incomplete room state to create game setup.");
       
   185 		} else {
       
   186 			result = flib_calloc(1, sizeof(flib_gamesetup));
       
   187 			if(result) {
       
   188 				result->gamescheme = flib_cfg_copy(conn->scheme);
       
   189 				result->map = flib_map_copy(conn->map);
       
   190 				result->script = flib_strdupnull(conn->script);
       
   191 				result->teamlist = flib_teamlist_create();
       
   192 				for(int i=0; i<conn->teamlist.teamCount; i++) {
       
   193 					flib_team *copy = flib_team_copy(conn->teamlist.teams[i]);
       
   194 					if(copy) {
       
   195 						flib_team_set_weaponset(copy, conn->weaponset);
       
   196 						flib_team_set_health(copy, conn->scheme->settings[2]); // TODO by name
       
   197 						flib_teamlist_insert(result->teamlist, copy, result->teamlist->teamCount);
       
   198 					}
       
   199 					flib_team_release(copy);
       
   200 				}
       
   201 				if(result->map->mapgen == MAPGEN_NAMED && result->map->name) {
       
   202 					flib_mapcfg mapcfg;
       
   203 					if(!flib_mapcfg_read(conn->dataDirPath, result->map->name, &mapcfg)) {
       
   204 						free(result->map->theme);
       
   205 						result->map->theme = flib_strdupnull(mapcfg.theme);
       
   206 					}
       
   207 				}
       
   208 				// TODO handle errors
       
   209 			}
       
   210 		}
       
   211 	}
       
   212 	return result;
   115 }
   213 }
   116 
   214 
   117 static void flib_netconn_wrappedtick(flib_netconn *conn) {
   215 static void flib_netconn_wrappedtick(flib_netconn *conn) {
   118 	flib_netmsg *netmsg;
   216 	flib_netmsg *netmsg;
   119 	flib_netbase *net = conn->netBase;
   217 	flib_netbase *net = conn->netBase;
   182 	        }
   280 	        }
   183 	    } else if(!strcmp(cmd, "ROOMS")) {
   281 	    } else if(!strcmp(cmd, "ROOMS")) {
   184 	        if(netmsg->partCount % 8 != 1) {
   282 	        if(netmsg->partCount % 8 != 1) {
   185 	        	flib_log_w("Net: Malformed ROOMS message");
   283 	        	flib_log_w("Net: Malformed ROOMS message");
   186 	        } else {
   284 	        } else {
   187 	        	flib_roomlist_clear(conn->roomList);
   285 	        	flib_roomlist_clear(&conn->roomList);
   188 	        	for(int i=1; i<netmsg->partCount; i+=8) {
   286 	        	for(int i=1; i<netmsg->partCount; i+=8) {
   189 	        		if(flib_roomlist_add(conn->roomList, netmsg->parts+i)) {
   287 	        		if(flib_roomlist_add(&conn->roomList, netmsg->parts+i)) {
   190 	        			flib_log_e("Error adding room to list in ROOMS message");
   288 	        			flib_log_e("Error adding room to list in ROOMS message");
   191 	        		}
   289 	        		}
   192 	        	}
   290 	        	}
   193 	        	if(conn->netconnState == NETCONN_STATE_CONNECTING) {
   291 	        	if(conn->netconnState == NETCONN_STATE_CONNECTING) {
   194 	        		// We delay the "connected" callback until now to ensure the room list is avaliable.
   292 	        		// We delay the "connected" callback until now to ensure the room list is avaliable.
   231 
   329 
   232 				for(int i=1; flags[i]; i++) {
   330 				for(int i=1; flags[i]; i++) {
   233 					switch(flags[i]) {
   331 					switch(flags[i]) {
   234 					case 'r':
   332 					case 'r':
   235 						for(int j = 2; j < netmsg->partCount; ++j) {
   333 						for(int j = 2; j < netmsg->partCount; ++j) {
   236 							conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[i], setFlag);
   334 							conn->onReadyStateCb(conn->onReadyStateCtx, netmsg->parts[j], setFlag);
   237 						}
   335 						}
   238 						break;
   336 						break;
   239 					default:
   337 					default:
   240 						flib_log_w("Net: Unknown flag %c in CLIENT_FLAGS message", flags[i]);
   338 						flib_log_w("Net: Unknown flag %c in CLIENT_FLAGS message", flags[i]);
   241 						break;
   339 						break;
   242 					}
   340 					}
   243 				}
   341 				}
   244 	        }
   342 	        }
   245 	    } else if (!strcmp(cmd, "ADD_TEAM")) {
   343 	    } else if (!strcmp(cmd, "ADD_TEAM")) {
   246 	        if(netmsg->partCount != 24) {
   344 	        if(netmsg->partCount != 24 || !flib_netconn_is_in_room_context(conn)) {
   247 	            flib_log_w("Net: Bad ADD_TEAM message");
   345 	            flib_log_w("Net: Bad ADD_TEAM message");
   248 	        } else {
   346 	        } else {
   249 	        	flib_team *team = flib_team_from_netmsg(netmsg->parts+1);
   347 	        	flib_team *team = flib_team_from_netmsg(netmsg->parts+1);
   250 	        	if(!team) {
   348 	        	flib_team *teamcopy = flib_team_from_netmsg(netmsg->parts+1);
       
   349 	        	if(!team || !teamcopy) {
   251 					conn->netconnState = NETCONN_STATE_DISCONNECTED;
   350 					conn->netconnState = NETCONN_STATE_DISCONNECTED;
   252 					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error");
   351 					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error");
   253 					exit = true;
   352 					exit = true;
   254 	        	} else {
   353 	        	} else {
   255 	        		team->remoteDriven = true;
   354 	        		team->remoteDriven = true;
       
   355 	        		teamcopy->remoteDriven = true;
       
   356 	        		flib_teamlist_insert(&conn->teamlist, teamcopy, conn->teamlist.teamCount);
   256 	        		conn->onTeamAddCb(conn->onTeamAddCtx, team);
   357 	        		conn->onTeamAddCb(conn->onTeamAddCtx, team);
   257 	        	}
   358 	        	}
   258 	        	flib_team_release(team);
   359 	        	flib_team_release(team);
       
   360 	        	flib_team_release(teamcopy);
   259 	        }
   361 	        }
   260 	    } else if (!strcmp(cmd, "REMOVE_TEAM")) {
   362 	    } else if (!strcmp(cmd, "REMOVE_TEAM")) {
   261 	        if(netmsg->partCount != 2) {
   363 	        if(netmsg->partCount != 2 || !flib_netconn_is_in_room_context(conn)) {
   262 	            flib_log_w("Net: Bad REMOVETEAM message");
   364 	            flib_log_w("Net: Bad REMOVETEAM message");
   263 	        } else {
   365 	        } else {
       
   366 	        	flib_teamlist_delete(&conn->teamlist, netmsg->parts[1]);
   264 	        	conn->onTeamDeleteCb(conn->onTeamDeleteCtx, netmsg->parts[1]);
   367 	        	conn->onTeamDeleteCb(conn->onTeamDeleteCtx, netmsg->parts[1]);
   265 	        }
   368 	        }
   266 	    } else if(!strcmp(cmd, "ROOMABANDONED")) {
   369 	    } else if(!strcmp(cmd, "ROOMABANDONED")) {
   267 	    	leaveRoom(conn);
   370 	    	netconn_leaveRoom(conn);
   268 	        conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed");
   371 	        conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed");
   269 	    } else if(!strcmp(cmd, "KICKED")) {
   372 	    } else if(!strcmp(cmd, "KICKED")) {
   270 	    	leaveRoom(conn);
   373 	    	netconn_leaveRoom(conn);
   271 	    	conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked");
   374 	    	conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked");
   272 	    } else if(!strcmp(cmd, "JOINED")) {
   375 	    } else if(!strcmp(cmd, "JOINED")) {
   273 	        if(netmsg->partCount < 2) {
   376 	        if(netmsg->partCount < 2) {
   274 	            flib_log_w("Net: Bad JOINED message");
   377 	            flib_log_w("Net: Bad JOINED message");
   275 	        } else {
   378 	        } else {
   310 	        	conn->onRoomLeaveCb(conn->onRoomLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
   413 	        	conn->onRoomLeaveCb(conn->onRoomLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
   311 	        }
   414 	        }
   312 	    } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) {
   415 	    } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) {
   313 	    	const char *subcmd = netmsg->parts[1];
   416 	    	const char *subcmd = netmsg->parts[1];
   314 	    	if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) {
   417 	    	if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) {
   315 	    		if(flib_roomlist_add(conn->roomList, netmsg->parts+2)) {
   418 	    		if(flib_roomlist_add(&conn->roomList, netmsg->parts+2)) {
   316 	    			flib_log_e("Error adding new room to list");
   419 	    			flib_log_e("Error adding new room to list");
   317 	    		} else {
   420 	    		} else {
   318 	    			conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList->rooms[0]);
   421 	    			conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList.rooms[0]);
   319 	    		}
   422 	    		}
   320 			} else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) {
   423 			} else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) {
   321 	    		if(flib_roomlist_update(conn->roomList, netmsg->parts[2], netmsg->parts+3)) {
   424 	    		if(flib_roomlist_update(&conn->roomList, netmsg->parts[2], netmsg->parts+3)) {
   322 	    			flib_log_e("Error updating room in list");
   425 	    			flib_log_e("Error updating room in list");
   323 	    		} else {
   426 	    		} else {
   324 	    			conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(conn->roomList, netmsg->parts[2]));
   427 	    			conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(&conn->roomList, netmsg->parts[2]));
   325 	    		}
   428 	    		}
   326 			} else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) {
   429 			} else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) {
   327 	    		if(flib_roomlist_delete(conn->roomList, netmsg->parts[2])) {
   430 	    		if(flib_roomlist_delete(&conn->roomList, netmsg->parts[2])) {
   328 	    			flib_log_e("Error deleting room from list");
   431 	    			flib_log_e("Error deleting room from list");
   329 	    		} else {
   432 	    		} else {
   330 	    			conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]);
   433 	    			conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]);
   331 	    		}
   434 	    		}
   332 			} else {
   435 			} else {
   338 	        } else {
   441 	        } else {
   339 	        	conn->onLobbyLeaveCb(conn->onLobbyLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
   442 	        	conn->onLobbyLeaveCb(conn->onLobbyLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
   340 	        }
   443 	        }
   341 	    } else if (!strcmp(cmd, "RUN_GAME")) {
   444 	    } else if (!strcmp(cmd, "RUN_GAME")) {
   342 	        conn->netconnState = NETCONN_STATE_INGAME;
   445 	        conn->netconnState = NETCONN_STATE_INGAME;
       
   446 	        // TODO send along the config
   343 	        conn->onRunGameCb(conn->onRunGameCtx);
   447 	        conn->onRunGameCb(conn->onRunGameCtx);
   344 	    } else if (!strcmp(cmd, "ASKPASSWORD")) {
   448 	    } else if (!strcmp(cmd, "ASKPASSWORD")) {
   345 	    	conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName);
   449 	    	conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName);
   346 	    } else if (!strcmp(cmd, "NOTICE")) {
   450 	    } else if (!strcmp(cmd, "NOTICE")) {
   347 	        if(netmsg->partCount < 2) {
   451 	        if(netmsg->partCount < 2) {
   356 				} else {
   460 				} else {
   357 					flib_log_w("Net: Unknown NOTICE message: %l", n);
   461 					flib_log_w("Net: Unknown NOTICE message: %l", n);
   358 				}
   462 				}
   359 	        }
   463 	        }
   360 	    } else if (!strcmp(cmd, "TEAM_ACCEPTED")) {
   464 	    } else if (!strcmp(cmd, "TEAM_ACCEPTED")) {
   361 	        if (netmsg->partCount != 2) {
   465 	        if (netmsg->partCount != 2 || !flib_netconn_is_in_room_context(conn)) {
   362 	            flib_log_w("Net: Bad TEAM_ACCEPTED message");
   466 	            flib_log_w("Net: Bad TEAM_ACCEPTED message");
   363 	        } else {
   467 	        } else {
       
   468 	        	flib_team *team = flib_teamlist_find(&conn->pendingTeamlist, netmsg->parts[1]);
       
   469 	        	if(team) {
       
   470 	        		flib_teamlist_insert(&conn->teamlist, team, conn->teamlist.teamCount);
       
   471 	        		flib_teamlist_delete(&conn->pendingTeamlist, netmsg->parts[1]);
       
   472 	        	} else {
       
   473 	        		flib_log_e("Team accepted that was not requested: %s", netmsg->parts[1]);
       
   474 	        	}
   364 	        	conn->onTeamAcceptedCb(conn->onTeamAcceptedCtx, netmsg->parts[1]);
   475 	        	conn->onTeamAcceptedCb(conn->onTeamAcceptedCtx, netmsg->parts[1]);
   365 	        }
   476 	        }
   366 	    } else if (!strcmp(cmd, "CFG")) {
   477 	    } else if (!strcmp(cmd, "CFG")) {
   367 	        if(netmsg->partCount < 3) {
   478 	        if(netmsg->partCount < 3 || !flib_netconn_is_in_room_context(conn)) {
   368 	            flib_log_w("Net: Bad CFG message");
   479 	            flib_log_w("Net: Bad CFG message");
   369 	        } else {
   480 	        } else {
   370 	        	const char *subcmd = netmsg->parts[1];
   481 	        	const char *subcmd = netmsg->parts[1];
   371 				if(!strcmp(subcmd, "SCHEME") && netmsg->partCount == conn->metaCfg->modCount + conn->metaCfg->settingCount + 3) {
   482 				if(!strcmp(subcmd, "SCHEME") && netmsg->partCount == conn->metaCfg->modCount + conn->metaCfg->settingCount + 3) {
   372 					flib_cfg *cfg = flib_netmsg_to_cfg(conn->metaCfg, netmsg->parts+2);
   483 					flib_cfg *cfg = flib_netmsg_to_cfg(conn->metaCfg, netmsg->parts+2);
   373 					if(cfg) {
   484 					if(cfg) {
       
   485 						netconn_setScheme(conn, cfg);
   374 						conn->onCfgSchemeCb(conn->onCfgSchemeCtx, cfg);
   486 						conn->onCfgSchemeCb(conn->onCfgSchemeCtx, cfg);
   375 					} else {
   487 					} else {
   376 						flib_log_e("Error processing CFG SCHEME message");
   488 						flib_log_e("Error processing CFG SCHEME message");
   377 					}
   489 					}
   378 					flib_cfg_release(cfg);
   490 					flib_cfg_release(cfg);
   379 				} else if(!strcmp(subcmd, "FULLMAPCONFIG") && netmsg->partCount == 7) {
   491 				} else if(!strcmp(subcmd, "FULLMAPCONFIG") && netmsg->partCount == 7) {
   380 					flib_map *map = flib_netmsg_to_map(netmsg->parts+2);
   492 					flib_map *map = flib_netmsg_to_map(netmsg->parts+2);
   381 					if(map) {
   493 					if(map) {
   382 						flib_map_release(conn->map);
   494 						netconn_setMap(conn, map);
   383 						conn->map = map;
       
   384 						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_FULL);
   495 						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_FULL);
   385 					} else {
   496 					} else {
   386 						flib_log_e("Error processing CFG FULLMAPCONFIG message");
   497 						flib_log_e("Error processing CFG FULLMAPCONFIG message");
   387 					}
   498 					}
       
   499 					flib_map_release(map);
   388 				} else if(!strcmp(subcmd, "MAP") && netmsg->partCount == 3) {
   500 				} else if(!strcmp(subcmd, "MAP") && netmsg->partCount == 3) {
   389 					char *mapname = flib_strdupnull(netmsg->parts[2]);
   501 					char *mapname = flib_strdupnull(netmsg->parts[2]);
   390 					if(mapname) {
   502 					if(mapname) {
   391 						free(conn->map->name);
   503 						free(conn->map->name);
   392 						conn->map->name = mapname;
   504 						conn->map->name = mapname;
   421 				} else if(!strcmp(subcmd, "MAZE_SIZE") && netmsg->partCount == 3) {
   533 				} else if(!strcmp(subcmd, "MAZE_SIZE") && netmsg->partCount == 3) {
   422 					conn->map->mazeSize = atoi(netmsg->parts[2]);
   534 					conn->map->mazeSize = atoi(netmsg->parts[2]);
   423 					conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAZE_SIZE);
   535 					conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAZE_SIZE);
   424 				} else if(!strcmp(subcmd, "DRAWNMAP") && netmsg->partCount == 3) {
   536 				} else if(!strcmp(subcmd, "DRAWNMAP") && netmsg->partCount == 3) {
   425 					size_t drawnMapSize = 0;
   537 					size_t drawnMapSize = 0;
   426 					uint8_t *drawnMapData = flib_netmsg_to_drawnmapdata(&drawnMapSize, netmsg->parts[2]);
   538 					uint8_t *drawnMapData = NULL;
   427 					if(drawnMapData) {
   539 					if(!flib_netmsg_to_drawnmapdata(netmsg->parts[2], &drawnMapData, &drawnMapSize)) {
   428 						free(conn->map->drawData);
   540 						free(conn->map->drawData);
   429 						conn->map->drawData = drawnMapData;
   541 						conn->map->drawData = drawnMapData;
   430 						conn->map->drawDataSize = drawnMapSize;
   542 						conn->map->drawDataSize = drawnMapSize;
   431 						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_DRAWNMAP);
   543 						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_DRAWNMAP);
   432 					} else {
   544 					} else {
   433 						flib_log_e("Error processing CFG DRAWNMAP message");
   545 						flib_log_e("Error processing CFG DRAWNMAP message");
   434 					}
   546 					}
   435 				} else if(!strcmp(subcmd, "SCRIPT") && netmsg->partCount == 3) {
   547 				} else if(!strcmp(subcmd, "SCRIPT") && netmsg->partCount == 3) {
       
   548 					netconn_setScript(conn, netmsg->parts[2]);
   436 					conn->onScriptChangedCb(conn->onScriptChangedCtx, netmsg->parts[2]);
   549 					conn->onScriptChangedCb(conn->onScriptChangedCtx, netmsg->parts[2]);
   437 				} else if(!strcmp(subcmd, "AMMO") && netmsg->partCount == 4) {
   550 				} else if(!strcmp(subcmd, "AMMO") && netmsg->partCount == 4) {
   438 					flib_weaponset *weapons = flib_weaponset_from_ammostring(netmsg->parts[2], netmsg->parts[3]);
   551 					flib_weaponset *weapons = flib_weaponset_from_ammostring(netmsg->parts[2], netmsg->parts[3]);
   439 					if(weapons) {
   552 					if(weapons) {
       
   553 						netconn_setWeaponset(conn, weapons);
   440 						conn->onWeaponsetChangedCb(conn->onWeaponsetChangedCtx, weapons);
   554 						conn->onWeaponsetChangedCb(conn->onWeaponsetChangedCtx, weapons);
   441 					} else {
   555 					} else {
   442 						flib_log_e("Error processing CFG AMMO message");
   556 						flib_log_e("Error processing CFG AMMO message");
   443 					}
   557 					}
   444 					flib_weaponset_release(weapons);
   558 					flib_weaponset_release(weapons);
   445 				} else {
   559 				} else {
   446 					flib_log_w("Net: Unknown or malformed CFG subcommand: %s", subcmd);
   560 					flib_log_w("Net: Unknown or malformed CFG subcommand: %s", subcmd);
   447 				}
   561 				}
   448 	        }
   562 	        }
   449 	    } else if (!strcmp(cmd, "HH_NUM")) {
   563 	    } else if (!strcmp(cmd, "HH_NUM")) {
   450 	        if (netmsg->partCount != 3) {
   564 	        if (netmsg->partCount != 3 || !flib_netconn_is_in_room_context(conn)) {
   451 	            flib_log_w("Net: Bad HH_NUM message");
   565 	            flib_log_w("Net: Bad HH_NUM message");
   452 	        } else {
   566 	        } else {
   453 	        	int hogs = atoi(netmsg->parts[2]);
   567 	        	int hogs = atoi(netmsg->parts[2]);
   454 	        	if(hogs<=0 || hogs>HEDGEHOGS_PER_TEAM) {
   568 	        	if(hogs<=0 || hogs>HEDGEHOGS_PER_TEAM) {
   455 	        		flib_log_w("Net: Bad HH_NUM message: %s hogs", netmsg->parts[2]);
   569 	        		flib_log_w("Net: Bad HH_NUM message: %s hogs", netmsg->parts[2]);
   456 	        	} else {
   570 	        	} else {
       
   571 	        		flib_team *team = flib_teamlist_find(&conn->teamlist, netmsg->parts[1]);
       
   572 	        		if(team) {
       
   573 	        			team->hogsInGame = hogs;
       
   574 	        		} else {
       
   575 	        			flib_log_e("HH_NUM message for unknown team %s", netmsg->parts[1]);
       
   576 	        		}
   457 	        		conn->onHogCountChangedCb(conn->onHogCountChangedCtx, netmsg->parts[1], hogs);
   577 	        		conn->onHogCountChangedCb(conn->onHogCountChangedCtx, netmsg->parts[1], hogs);
   458 	        	}
   578 	        	}
   459 	        }
   579 	        }
   460 	    } else if (!strcmp(cmd, "TEAM_COLOR")) {
   580 	    } else if (!strcmp(cmd, "TEAM_COLOR")) {
   461 	        if (netmsg->partCount != 3) {
   581 	        if (netmsg->partCount != 3 || !flib_netconn_is_in_room_context(conn)) {
   462 	            flib_log_w("Net: Bad TEAM_COLOR message");
   582 	            flib_log_w("Net: Bad TEAM_COLOR message");
   463 	        } else {
   583 	        } else {
   464 	        	long color;
   584 	        	long color;
   465 	        	if(sscanf(netmsg->parts[2], "#%lx", &color)) {
   585 	        	if(sscanf(netmsg->parts[2], "%lu", &color) && color>=0 && color<flib_teamcolor_defaults_len) {
   466 	        		conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], (uint32_t)color);
   586 	        		flib_team *team = flib_teamlist_find(&conn->teamlist, netmsg->parts[1]);
       
   587 	        		if(team) {
       
   588 	        			team->colorIndex = color;
       
   589 	        		} else {
       
   590 	        			flib_log_e("TEAM_COLOR message for unknown team %s", netmsg->parts[1]);
       
   591 	        		}
       
   592 	        		conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], color);
   467 	        	} else {
   593 	        	} else {
   468 	        		flib_log_w("Net: Bad TEAM_COLOR message: Color %s", netmsg->parts[2]);
   594 	        		flib_log_w("Net: Bad TEAM_COLOR message: Color %s", netmsg->parts[2]);
   469 	        	}
   595 	        	}
   470 	        }
   596 	        }
   471 	    } else if (!strcmp(cmd, "EM")) {
   597 	    } else if (!strcmp(cmd, "EM")) {
   475 	        	for(int i = 1; i < netmsg->partCount; ++i) {
   601 	        	for(int i = 1; i < netmsg->partCount; ++i) {
   476 					char *out = NULL;
   602 					char *out = NULL;
   477 					size_t outlen;
   603 					size_t outlen;
   478 					bool ok = base64_decode_alloc(netmsg->parts[i], strlen(netmsg->parts[i]), &out, &outlen);
   604 					bool ok = base64_decode_alloc(netmsg->parts[i], strlen(netmsg->parts[i]), &out, &outlen);
   479 					if(ok && outlen) {
   605 					if(ok && outlen) {
   480 						conn->onEngineMessageCb(conn->onEngineMessageCtx, out, outlen);
   606 						conn->onEngineMessageCb(conn->onEngineMessageCtx, (uint8_t*)out, outlen);
   481 					} else {
   607 					} else {
   482 						flib_log_e("Net: Malformed engine message: %s", netmsg->parts[i]);
   608 						flib_log_e("Net: Malformed engine message: %s", netmsg->parts[i]);
   483 					}
   609 					}
   484 					free(out);
   610 					free(out);
   485 	        	}
   611 	        	}