[Top][All Lists]
[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)
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Wesnoth-cvs-commits] wesnoth/src/server server.cpp,
David White <=