wesnoth-cvs-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Wesnoth-cvs-commits] wesnoth/src/server server.cpp


From: David White
Subject: [Wesnoth-cvs-commits] wesnoth/src/server server.cpp
Date: Sun, 20 Feb 2005 16:37:14 -0500

CVSROOT:        /cvsroot/wesnoth
Module name:    wesnoth
Branch:         
Changes by:     David White <address@hidden>    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)
 {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]