[Wesnoth-cvs-commits] wesnoth/src/server server.cpp (February 20, 2005 - 22:52)

 

CVSROOT:	/cvsroot/wesnoth
Module name:	wesnoth
Branch: 	
Changes by:	David White <Sirp@xxxxxxxxxxxxxxxx>	05/02/20 21:37:14

Modified files:
	src/server     : server.cpp 

Log message:
	refactor of server code

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/server/server.cpp.diff?tr1=1.63&tr2=1.64&r1=text&r2=text

Patches:
Index: wesnoth/src/server/server.cpp
diff -u wesnoth/src/server/server.cpp:1.63 wesnoth/src/server/server.cpp:1.64
--- wesnoth/src/server/server.cpp:1.63	Fri Dec 31 21:01:38 2004
+++ wesnoth/src/server/server.cpp	Sun Feb 20 21:37:14 2005
@@ -63,7 +63,14 @@
 public:
 	server(int port, input_stream& input);
 	void run();
-private:
+private:
+	void process_data(network::connection sock, config& data, config& gamelist);
+
+	void process_login(network::connection sock, const config& data, config& gamelist);
+	void process_query(network::connection sock, const config& query, config& gamelist);
+	void process_data_from_player_in_lobby(network::connection sock, config& data, config& gamelist);
+	void process_data_from_player_in_game(network::connection sock, config& data, config& gamelist);
+
 	void process_command(const std::string& cmd);
 
 	void delete_game(std::vector<game>::iterator i);
@@ -278,469 +285,8 @@
 			config data;
 			while((sock = network::receive_data(data)) != network::null_connection) {
 
-				metrics_.service_request();
-
-				//if someone who is not yet logged in is sending
-				//login details
-				if(not_logged_in_.is_member(sock)) {
-					const config* const login = data.child("login");
-
-					//client must send a login first.
-					if(login == NULL) {
-						network::send_data(construct_error(
-						                   "You must login first"),sock);
-						continue;
-					}
-
-					//check the username is valid (all alpha-numeric or space)
-					std::string username = (*login)["username"];
-					config::strip(username);
-					const int alnum = std::count_if(username.begin(),username.end(),isalnum);
-					const int spaces = std::count(username.begin(),username.end(),' ');
-					if((alnum + spaces != username.size()) || spaces == username.size() || username.empty()) {
-						network::send_data(construct_error(
-						                   "This username is not valid"),sock);
-						continue;
-					}
-
-					if(username.size() > 32) {
-						network::send_data(construct_error(
-						                   "This username is too long"),sock);
-						continue;
-					}
-
-					if(username == "server") {
-						network::send_data(construct_error(
-						                   "The nick 'server' is reserved and can not be used by players"),sock);
-						continue;
-					}
-
-					//check the username isn't already taken
-					player_map::const_iterator p;
-					for(p = players_.begin(); p != players_.end(); ++p) {
-						if(p->second.name() == username) {
-							break;
-						}
-					}
-
-					if(p != players_.end()) {
-						network::send_data(construct_error(
-						              "This username is already taken"),sock);
-						continue;
-					}
-					
-					config* const player_cfg = &initial_response_.add_child("user");
-
-					const player new_player(username,*player_cfg);
-
-					players_.insert(std::pair<network::connection,player>(sock,new_player));
-
-					//remove player from the not-logged-in list and place
-					//the player in the lobby
-					not_logged_in_.remove_player(sock);
-					lobby_players_.add_player(sock);
-
-					//send the new player the entire list of games and players
-					network::send_data(initial_response_,sock);
-
-					//send other players in the lobby the update that the player has joined
-					lobby_players_.send_data(sync_initial_response(),sock);
-
-					std::cerr << "'" << username << "' (" << network::ip_address(sock) << ") has logged on\n";
-
-					for(std::vector<game>::iterator g = games_.begin(); g != games_.end(); ++g) {
-						g->send_data_observers(construct_server_message(username + " has logged into the lobby",*g));
-					}
-
-				} else if(const config* query = data.child("query")) {
-
-					//process queries from clients in here
-					std::ostringstream response;
-					if((*query)["type"] == "metrics") {
-						//a query for server data from a player
-						response << metrics_;	
-					} else {
-						response << "Error: unrecognized query";
-					}
-					
-					network::send_data(construct_server_message(response.str(),lobby_players_),sock);
-				} else if(lobby_players_.is_member(sock)) {
-					const config* const create_game = data.child("create_game");
-					if(create_game != NULL) {
-
-						std::cerr << "creating game...\n";
-
-						//create the new game, remove the player from the
-						//lobby and put him/her in the game they have created
-						games_.push_back(game(players_));
-						lobby_players_.remove_player(sock);
-						games_.back().add_player(sock);
-
-						//store the game data here at the moment
-						games_.back().level() = *create_game;
-						std::stringstream converter;
-						converter << games_.back().id();
-						games_.back().level()["id"] = converter.str();
-
-						//mark the player as unavailable in the lobby
-						const player_map::iterator pl = players_.find(sock);
-						if(pl != players_.end()) {
-							pl->second.mark_available(false);
-
-							lobby_players_.send_data(sync_initial_response());
-						} else {
-							std::cerr << "ERROR: Could not find player in map\n";
-						}
-
-						continue;
-					}
-
-					//see if the player is joining a game
-					const config* const join = data.child("join");
-					if(join != NULL) {
-						const std::string& id = (*join)["id"];
-						const int nid = atoi(id.c_str());
-						const std::vector<game>::iterator it =
-						             std::find_if(games_.begin(),games_.end(),
-						                          game_id_matches(nid));
-						if(it == games_.end()) {
-							//send a response saying the game has been cancelled
-							config cfg;
-							cfg.add_child("leave_game");
-							network::send_data(cfg,sock);
-
-							std::cerr << "attempt to join unknown game\n";
-							continue;
-						}
-
-						if(it->player_is_banned(sock)) {
-							network::send_data(construct_error("You are banned from this game"),sock);
-							continue;
-						}
-
-						lobby_players_.remove_player(sock);
-
-						//send them the game data
-						network::send_data(it->level(),sock);
-
-						it->add_player(sock);
-
-						//mark the player as unavailable in the lobby
-						const player_map::iterator pl = players_.find(sock);
-						if(pl != players_.end()) {
-							pl->second.mark_available(false);
-
-							lobby_players_.send_data(sync_initial_response());
-						} else {
-							std::cerr << "ERROR: Could not find player in map\n";
-						}
-					}
-
-					//see if it's a message, in which case we add the name
-					//of the sender, and forward it to all players in the lobby
-					config* const message = data.child("message");
-					if(message != NULL) {
-						const player_map::const_iterator p = players_.find(sock);
-						wassert(p != players_.end());
-						(*message)["sender"] = p->second.name();
-
-						truncate_message((*message)["message"]);
-
-						lobby_players_.send_data(data,sock);
-					}
-				} else {
-					std::vector<game>::iterator g;
-					for(g = games_.begin(); g != games_.end(); ++g) {
-						if(g->is_member(sock))
-							break;
-					}
-
-					if(g == games_.end()) {
-						std::cerr << "ERROR: unknown socket " << games_.size() << "\n";
-						continue;
-					}
-
-					//if info is being provided about the game state
-					if(data.child("info") != NULL) {
-						const config& info = *data.child("info");
-						if(info["type"] == "termination") {
-							g->set_termination_reason(info["condition"]);
-						}
-					}
-
-					//if the owner is changing the controller for a side
-					if(g->is_owner(sock) && data.child("change_controller") != NULL) {
-						const config& change = *data.child("change_controller");
-						const std::string& result = g->transfer_side_control(change);
-						if(result == "") {
-							const config& msg = construct_server_message(change["player"] + " takes control of side " + change["side"],*g);
-							g->send_data(msg);
-						} else {
-							const config& msg = construct_server_message(result,*g);
-							network::send_data(msg,sock);
-						}
-
-						continue;
-					}
-
-					//if the owner is banning someone from the game
-					if(g->is_owner(sock) && data.child("ban") != NULL) {
-						const config& ban = *data.child("ban");
-						const std::string& name = ban["username"];
-						player_map::iterator pl;
-						for(pl = players_.begin(); pl != players_.end(); ++pl) {
-							if(pl->second.name() == name) {
-								break;
-							}
-						}
-
-						if(pl->first != sock && pl != players_.end()) {
-							g->ban_player(pl->first);
-							const config& msg = construct_server_message("You have been banned",*g);
-							network::send_data(msg,pl->first);
-							config leave_game;
-							leave_game.add_child("leave_game");
-							network::send_data(leave_game,pl->first);
-
-							g->describe_slots();
-							lobby_players_.add_player(pl->first);
-
-							//mark the player as available in the lobby
-							pl->second.mark_available(true);
-
-							//send the player who was banned the lobby game list
-							network::send_data(initial_response_,pl->first);
-
-							//send all other players in the lobby the update to the lobby
-							lobby_players_.send_data(sync_initial_response(),sock);
-						} else if(pl == players_.end()) {
-							const config& response = construct_server_message(
-							             "Ban failed: user '" + name + "' not found",*g);
-							network::send_data(response,sock);
-						}
-					} else if(data.child("ban")) {
-						const config& response = construct_server_message(
-						             "You cannot ban: not the game creator",*g);
-						network::send_data(response,sock);
-					}
-
-					//if this is data describing changes to a game.
-					else if(g->is_owner(sock) && data.child("scenario_diff")) {
-						g->level().apply_diff(*data.child("scenario_diff"));
-						g->send_data(data,sock);
-
-						const bool lobby_changes = g->describe_slots();
-						if(lobby_changes) {
-							lobby_players_.send_data(sync_initial_response());
-						}
-					}
-
-					//if this is data describing the level for a game.
-					else if(g->is_owner(sock) && data.child("side") != NULL) {
-
-						const bool is_init = g->level_init();
-
-						//if this game is having its level data initialized
-						//for the first time, and is ready for players to join.
-						//We should currently have a summary of the game in g->level().
-						//we want to move this summary to the initial_response_, and
-						//place a pointer to that summary in the game's description.
-						//g->level() should then receive the full data for the game.
-						if(!is_init) {
-
-							//if there is no shroud, then tell players in the lobby what the map looks like
-							if((*data.child("side"))["shroud"] != "yes") {
-								g->level().values["map_data"] = data["map_data"];
-								g->level().values["map"] = data["map"];
-							}
-							
-							//update our config object which describes the
-							//open games, and notifies the game of where its description
-							//is located at
-							config& desc = gamelist.add_child("game",g->level());
-							g->set_description(&desc);
-
-							//record the full description of the scenario in g->level()
-							g->level() = data;
-							g->describe_slots();
-
-							//send all players in the lobby the update to the list of games
-							lobby_players_.send_data(sync_initial_response());
-						} else {
-
-							//we've already initialized this scenario, but clobber its old
-							//contents with the new ones given here
-							g->level() = data;
-						}
-
-						//send all players in the level, except the sender, the new data
-						g->send_data(data,sock);
-						continue;
-					}
-
-					const string_map::const_iterator side = data.values.find("side");
-					if(side != data.values.end()) {
-						const bool res = g->take_side(sock,data);
-						config response;
-						if(res) {
-							std::cerr << "played joined side\n";
-							response["side_secured"] = side->second;
-
-							//update the number of available slots
-							const bool res = g->describe_slots();
-							if(res) {
-								lobby_players_.send_data(sync_initial_response());
-							}
-						} else {
-							response["failed"] = "yes";
-						}
-
-						network::send_data(response,sock);
-						continue;
-					}
-
-					if(data.child("start_game")) {
-						//send notification of the game starting immediately.
-						//g->start_game() will send data that assumes the [start_game]
-						//message has been sent
-						g->send_data(data,sock);
-
-						g->start_game();
-						lobby_players_.send_data(sync_initial_response());
-						continue;
-					} else if(data.child("leave_game")) {
-						const bool needed = g->is_needed(sock);
-
-						if(needed) {
-
-							//tell all other players the game is over,
-							//because a needed player has left
-							config cfg;
-							cfg.add_child("leave_game");
-							g->send_data(cfg);
-
-							//delete the game's description
-							config* const gamelist = initial_response_.child("gamelist");
-							wassert(gamelist != NULL);
-							const config::child_itors vg = gamelist->child_range("game");
-
-							const config::child_iterator desc = std::find(vg.first,vg.second,g->description());
-							if(desc != vg.second) {
-								gamelist->remove_child("game",desc - vg.first);
-							}
-
-							//update the state of the lobby to players in it.
-							//We have to sync the state of the lobby so we can
-							//send it to the players leaving the game
-							lobby_players_.send_data(sync_initial_response());
-
-							//set the availability status for all quitting players
-							for(player_map::iterator pl = players_.begin(); pl != players_.end(); ++pl) {
-								if(g->is_member(pl->first)) {
-									pl->second.mark_available(true);
-								}
-							}
-
-							//put the players back in the lobby and send
-							//them the game list and user list again
-							g->send_data(initial_response_);
-							metrics_.game_terminated(g->termination_reason());
-							lobby_players_.add_players(*g);
-							games_.erase(g);
-
-							//now sync players in the lobby again, to remove the game
-							lobby_players_.send_data(sync_initial_response());
-						} else {
-
-							g->remove_player(sock);
-							g->describe_slots();
-							lobby_players_.add_player(sock);
-
-							//mark the player as available in the lobby
-							const player_map::iterator pl = players_.find(sock);
-							if(pl != players_.end()) {
-								pl->second.mark_available(true);
-							} else {
-								std::cerr << "ERROR: Could not find player in map\n";
-							}
-
-							//send the player who has quit the game list
-							network::send_data(initial_response_,sock);
-
-							//send all other players in the lobby the update to the lobby
-							lobby_players_.send_data(sync_initial_response(),sock);
-						}
-
-						continue;
-					} else if(data["side_secured"].empty() == false) {
-						continue;
-					} else if(data["failed"].empty() == false) {
-						std::cerr << "ERROR: failure to get side\n";
-						continue;
-					}
-
-					config* const turn = data.child("turn");
-					if(turn != NULL) {
-						g->filter_commands(sock,*turn);
-
-						//notify the game of the commands, and if it changes
-						//the description, then sync the new description
-						//to players in the lobby
-						const bool res = g->process_commands(*turn);
-						if(res) {
-							lobby_players_.send_data(sync_initial_response());
-						}
-
-						//any private 'speak' commands must be repackaged seperate
-						//to other commands, and re-sent, since they should only go
-						//to some clients.
-						const config::child_itors speaks = turn->child_range("command");
-						int npublic = 0, nprivate = 0, nother = 0;
-						std::string team_name;
-						for(config::child_iterator i = speaks.first; i != speaks.second; ++i) {
-							config* const speak = (*i)->child("speak");
-							if(speak == NULL) {
-								++nother;
-								continue;
-							}
-
-							truncate_message((*speak)["message"]);
-
-							//force the description to be correct to prevent
-							//spoofing of messages
-							const player_map::const_iterator pl = players_.find(sock);
-							wassert(pl != players_.end());
-							(*speak)["description"] = pl->second.name();
-
-							if((*speak)["team_name"] == "") {
-								++npublic;
-							} else {
-								++nprivate;
-								team_name = (*speak)["team_name"];
-							}
-						}
-
-						//if all there are are messages and they're all private, then
-						//just forward them on to the client that should receive them.
-						if(nprivate > 0 && npublic == 0 && nother == 0) {
-							g->send_data_team(data,team_name,sock);
-							continue;
-						}
-
-						//at the moment, if private messages are mixed in with other
-						//data, then let them go through. It's exceedingly unlikely that
-						//this will happen anyway, and if it does, the client should
-						//respect not displaying the message.
-					}
-
-					//forward data to all players who are in the game,
-					//except for the original data sender
-					g->send_data(data,sock);
-
-					if(g->started()) {
-						g->record_data(data);
-					}
-				}
+				metrics_.service_request();
+				process_data(sock,data,gamelist);
 			}
 
 			metrics_.no_requests();
@@ -792,6 +338,489 @@
 		SDL_Delay(20);
 	}
 }
+
+void server::process_data(const network::connection sock, config& data, config& gamelist)
+{
+	//if someone who is not yet logged in is sending
+	//login details
+	if(not_logged_in_.is_member(sock)) {
+		process_login(sock,data,gamelist);
+	} else if(const config* query = data.child("query")) {
+		process_query(sock,*query,gamelist);
+	} else if(lobby_players_.is_member(sock)) {
+		process_data_from_player_in_lobby(sock,data,gamelist);
+	} else {
+		process_data_from_player_in_game(sock,data,gamelist);
+	}
+}
+
+void server::process_login(const network::connection sock, const config& data, config& gamelist)
+{
+	const config* const login = data.child("login");
+
+	//client must send a login first.
+	if(login == NULL) {
+		network::send_data(construct_error(
+		                   "You must login first"),sock);
+		return;
+	}
+
+	//check the username is valid (all alpha-numeric or space)
+	std::string username = (*login)["username"];
+	config::strip(username);
+	const int alnum = std::count_if(username.begin(),username.end(),isalnum);
+	const int spaces = std::count(username.begin(),username.end(),' ');
+	if((alnum + spaces != username.size()) || spaces == username.size() || username.empty()) {
+		network::send_data(construct_error(
+		                   "This username is not valid"),sock);
+		return;
+	}
+
+	if(username.size() > 32) {
+		network::send_data(construct_error(
+		                   "This username is too long"),sock);
+		return;
+	}
+
+	if(username == "server") {
+		network::send_data(construct_error(
+		                   "The nick 'server' is reserved and can not be used by players"),sock);
+		return;
+	}
+
+	//check the username isn't already taken
+	player_map::const_iterator p;
+	for(p = players_.begin(); p != players_.end(); ++p) {
+		if(p->second.name() == username) {
+			break;
+		}
+	}
+
+	if(p != players_.end()) {
+		network::send_data(construct_error(
+		              "This username is already taken"),sock);
+		return;
+	}
+	
+	config* const player_cfg = &initial_response_.add_child("user");
+
+	const player new_player(username,*player_cfg);
+
+	players_.insert(std::pair<network::connection,player>(sock,new_player));
+
+	//remove player from the not-logged-in list and place
+	//the player in the lobby
+	not_logged_in_.remove_player(sock);
+	lobby_players_.add_player(sock);
+
+	//send the new player the entire list of games and players
+	network::send_data(initial_response_,sock);
+
+	//send other players in the lobby the update that the player has joined
+	lobby_players_.send_data(sync_initial_response(),sock);
+
+	std::cerr << "'" << username << "' (" << network::ip_address(sock) << ") has logged on\n";
+
+	for(std::vector<game>::iterator g = games_.begin(); g != games_.end(); ++g) {
+		g->send_data_observers(construct_server_message(username + " has logged into the lobby",*g));
+	}
+}
+
+void server::process_query(const network::connection sock, const config& query, config& gamelist)
+{
+	//process queries from clients in here
+	std::ostringstream response;
+	if(query["type"] == "metrics") {
+		//a query for server data from a player
+		response << metrics_;	
+	} else {
+		response << "Error: unrecognized query";
+	}
+		
+	network::send_data(construct_server_message(response.str(),lobby_players_),sock);
+}
+
+void server::process_data_from_player_in_lobby(const network::connection sock, config& data, config& gamelist)
+{
+	const config* const create_game = data.child("create_game");
+	if(create_game != NULL) {
+
+		std::cerr << "creating game...\n";
+
+		//create the new game, remove the player from the
+		//lobby and put him/her in the game they have created
+		games_.push_back(game(players_));
+		lobby_players_.remove_player(sock);
+		games_.back().add_player(sock);
+
+		//store the game data here at the moment
+		games_.back().level() = *create_game;
+		std::stringstream converter;
+		converter << games_.back().id();
+		games_.back().level()["id"] = converter.str();
+
+		//mark the player as unavailable in the lobby
+		const player_map::iterator pl = players_.find(sock);
+		if(pl != players_.end()) {
+			pl->second.mark_available(false);
+
+			lobby_players_.send_data(sync_initial_response());
+		} else {
+			std::cerr << "ERROR: Could not find player in map\n";
+		}
+
+		return;
+	}
+
+	//see if the player is joining a game
+	const config* const join = data.child("join");
+	if(join != NULL) {
+		const std::string& id = (*join)["id"];
+		const int nid = atoi(id.c_str());
+		const std::vector<game>::iterator it =
+		             std::find_if(games_.begin(),games_.end(),
+		                          game_id_matches(nid));
+		if(it == games_.end()) {
+			//send a response saying the game has been cancelled
+			config cfg;
+			cfg.add_child("leave_game");
+			network::send_data(cfg,sock);
+
+			std::cerr << "attempt to join unknown game\n";
+			return;
+		}
+
+		if(it->player_is_banned(sock)) {
+			network::send_data(construct_error("You are banned from this game"),sock);
+			return;
+		}
+
+		lobby_players_.remove_player(sock);
+
+		//send them the game data
+		network::send_data(it->level(),sock);
+
+		it->add_player(sock);
+
+		//mark the player as unavailable in the lobby
+		const player_map::iterator pl = players_.find(sock);
+		if(pl != players_.end()) {
+			pl->second.mark_available(false);
+
+			lobby_players_.send_data(sync_initial_response());
+		} else {
+			std::cerr << "ERROR: Could not find player in map\n";
+		}
+	}
+
+	//see if it's a message, in which case we add the name
+	//of the sender, and forward it to all players in the lobby
+	config* const message = data.child("message");
+	if(message != NULL) {
+		const player_map::const_iterator p = players_.find(sock);
+		wassert(p != players_.end());
+		(*message)["sender"] = p->second.name();
+
+		truncate_message((*message)["message"]);
+
+		lobby_players_.send_data(data,sock);
+	}
+}
+
+void server::process_data_from_player_in_game(const network::connection sock, config& data, config& gamelist)
+{
+	std::vector<game>::iterator g;
+	for(g = games_.begin(); g != games_.end(); ++g) {
+		if(g->is_member(sock))
+			break;
+	}
+
+	if(g == games_.end()) {
+		std::cerr << "ERROR: unknown socket " << games_.size() << "\n";
+		return;
+	}
+
+	//if info is being provided about the game state
+	if(data.child("info") != NULL) {
+		const config& info = *data.child("info");
+		if(info["type"] == "termination") {
+			g->set_termination_reason(info["condition"]);
+		}
+	}
+
+	//if the owner is changing the controller for a side
+	if(g->is_owner(sock) && data.child("change_controller") != NULL) {
+		const config& change = *data.child("change_controller");
+		const std::string& result = g->transfer_side_control(change);
+		if(result == "") {
+			const config& msg = construct_server_message(change["player"] + " takes control of side " + change["side"],*g);
+			g->send_data(msg);
+		} else {
+			const config& msg = construct_server_message(result,*g);
+			network::send_data(msg,sock);
+		}
+
+		return;
+	}
+
+	//if the owner is banning someone from the game
+	if(g->is_owner(sock) && data.child("ban") != NULL) {
+		const config& ban = *data.child("ban");
+		const std::string& name = ban["username"];
+		player_map::iterator pl;
+		for(pl = players_.begin(); pl != players_.end(); ++pl) {
+			if(pl->second.name() == name) {
+				break;
+			}
+		}
+
+		if(pl->first != sock && pl != players_.end()) {
+			g->ban_player(pl->first);
+			const config& msg = construct_server_message("You have been banned",*g);
+			network::send_data(msg,pl->first);
+			config leave_game;
+			leave_game.add_child("leave_game");
+			network::send_data(leave_game,pl->first);
+
+			g->describe_slots();
+			lobby_players_.add_player(pl->first);
+
+			//mark the player as available in the lobby
+			pl->second.mark_available(true);
+
+			//send the player who was banned the lobby game list
+			network::send_data(initial_response_,pl->first);
+
+			//send all other players in the lobby the update to the lobby
+			lobby_players_.send_data(sync_initial_response(),sock);
+		} else if(pl == players_.end()) {
+			const config& response = construct_server_message(
+			             "Ban failed: user '" + name + "' not found",*g);
+			network::send_data(response,sock);
+		}
+	} else if(data.child("ban")) {
+		const config& response = construct_server_message(
+		             "You cannot ban: not the game creator",*g);
+		network::send_data(response,sock);
+	}
+
+	//if this is data describing changes to a game.
+	else if(g->is_owner(sock) && data.child("scenario_diff")) {
+		g->level().apply_diff(*data.child("scenario_diff"));
+		g->send_data(data,sock);
+
+		const bool lobby_changes = g->describe_slots();
+		if(lobby_changes) {
+			lobby_players_.send_data(sync_initial_response());
+		}
+	}
+
+	//if this is data describing the level for a game.
+	else if(g->is_owner(sock) && data.child("side") != NULL) {
+
+		const bool is_init = g->level_init();
+
+		//if this game is having its level data initialized
+		//for the first time, and is ready for players to join.
+		//We should currently have a summary of the game in g->level().
+		//we want to move this summary to the initial_response_, and
+		//place a pointer to that summary in the game's description.
+		//g->level() should then receive the full data for the game.
+		if(!is_init) {
+
+			//if there is no shroud, then tell players in the lobby what the map looks like
+			if((*data.child("side"))["shroud"] != "yes") {
+				g->level().values["map_data"] = data["map_data"];
+				g->level().values["map"] = data["map"];
+			}
+			
+			//update our config object which describes the
+			//open games, and notifies the game of where its description
+			//is located at
+			config& desc = gamelist.add_child("game",g->level());
+			g->set_description(&desc);
+
+			//record the full description of the scenario in g->level()
+			g->level() = data;
+			g->describe_slots();
+
+			//send all players in the lobby the update to the list of games
+			lobby_players_.send_data(sync_initial_response());
+		} else {
+
+			//we've already initialized this scenario, but clobber its old
+			//contents with the new ones given here
+			g->level() = data;
+		}
+
+		//send all players in the level, except the sender, the new data
+		g->send_data(data,sock);
+		return;
+	}
+
+	const string_map::const_iterator side = data.values.find("side");
+	if(side != data.values.end()) {
+		const bool res = g->take_side(sock,data);
+		config response;
+		if(res) {
+			std::cerr << "played joined side\n";
+			response["side_secured"] = side->second;
+
+			//update the number of available slots
+			const bool res = g->describe_slots();
+			if(res) {
+				lobby_players_.send_data(sync_initial_response());
+			}
+		} else {
+			response["failed"] = "yes";
+		}
+
+		network::send_data(response,sock);
+		return;
+	}
+
+	if(data.child("start_game")) {
+		//send notification of the game starting immediately.
+		//g->start_game() will send data that assumes the [start_game]
+		//message has been sent
+		g->send_data(data,sock);
+
+		g->start_game();
+		lobby_players_.send_data(sync_initial_response());
+		return;
+	} else if(data.child("leave_game")) {
+		const bool needed = g->is_needed(sock);
+
+		if(needed) {
+
+			//tell all other players the game is over,
+			//because a needed player has left
+			config cfg;
+			cfg.add_child("leave_game");
+			g->send_data(cfg);
+
+			//delete the game's description
+			config* const gamelist = initial_response_.child("gamelist");
+			wassert(gamelist != NULL);
+			const config::child_itors vg = gamelist->child_range("game");
+
+			const config::child_iterator desc = std::find(vg.first,vg.second,g->description());
+			if(desc != vg.second) {
+				gamelist->remove_child("game",desc - vg.first);
+			}
+
+			//update the state of the lobby to players in it.
+			//We have to sync the state of the lobby so we can
+			//send it to the players leaving the game
+			lobby_players_.send_data(sync_initial_response());
+
+			//set the availability status for all quitting players
+			for(player_map::iterator pl = players_.begin(); pl != players_.end(); ++pl) {
+				if(g->is_member(pl->first)) {
+					pl->second.mark_available(true);
+				}
+			}
+
+			//put the players back in the lobby and send
+			//them the game list and user list again
+			g->send_data(initial_response_);
+			metrics_.game_terminated(g->termination_reason());
+			lobby_players_.add_players(*g);
+			games_.erase(g);
+
+			//now sync players in the lobby again, to remove the game
+			lobby_players_.send_data(sync_initial_response());
+		} else {
+
+			g->remove_player(sock);
+			g->describe_slots();
+			lobby_players_.add_player(sock);
+
+			//mark the player as available in the lobby
+			const player_map::iterator pl = players_.find(sock);
+			if(pl != players_.end()) {
+				pl->second.mark_available(true);
+			} else {
+				std::cerr << "ERROR: Could not find player in map\n";
+			}
+
+			//send the player who has quit the game list
+			network::send_data(initial_response_,sock);
+
+			//send all other players in the lobby the update to the lobby
+			lobby_players_.send_data(sync_initial_response(),sock);
+		}
+
+		return;
+	} else if(data["side_secured"].empty() == false) {
+		return;
+	} else if(data["failed"].empty() == false) {
+		std::cerr << "ERROR: failure to get side\n";
+		return;
+	}
+
+	config* const turn = data.child("turn");
+	if(turn != NULL) {
+		g->filter_commands(sock,*turn);
+
+		//notify the game of the commands, and if it changes
+		//the description, then sync the new description
+		//to players in the lobby
+		const bool res = g->process_commands(*turn);
+		if(res) {
+			lobby_players_.send_data(sync_initial_response());
+		}
+
+		//any private 'speak' commands must be repackaged seperate
+		//to other commands, and re-sent, since they should only go
+		//to some clients.
+		const config::child_itors speaks = turn->child_range("command");
+		int npublic = 0, nprivate = 0, nother = 0;
+		std::string team_name;
+		for(config::child_iterator i = speaks.first; i != speaks.second; ++i) {
+			config* const speak = (*i)->child("speak");
+			if(speak == NULL) {
+				++nother;
+				continue;
+			}
+
+			truncate_message((*speak)["message"]);
+
+			//force the description to be correct to prevent
+			//spoofing of messages
+			const player_map::const_iterator pl = players_.find(sock);
+			wassert(pl != players_.end());
+			(*speak)["description"] = pl->second.name();
+
+			if((*speak)["team_name"] == "") {
+				++npublic;
+			} else {
+				++nprivate;
+				team_name = (*speak)["team_name"];
+			}
+		}
+
+		//if all there are are messages and they're all private, then
+		//just forward them on to the client that should receive them.
+		if(nprivate > 0 && npublic == 0 && nother == 0) {
+			g->send_data_team(data,team_name,sock);
+			return;
+		}
+
+		//at the moment, if private messages are mixed in with other
+		//data, then let them go through. It's exceedingly unlikely that
+		//this will happen anyway, and if it does, the client should
+		//respect not displaying the message.
+	}
+
+	//forward data to all players who are in the game,
+	//except for the original data sender
+	g->send_data(data,sock);
+
+	if(g->started()) {
+		g->record_data(data);
+	}
+}
 
 void server::delete_game(std::vector<game>::iterator i)
 {



You are on the gna.org mail server.

Generated by mhonarc, Tue Sep 20 16:46:54 2005