fixes bug #6021 (problems with host handover functionality)

This also changes the control command in the way that every player can
give away his own slot(s).
This commit is contained in:
Jörg Hinrichs 2006-06-07 20:45:42 +00:00
parent bf78bab759
commit b62e6dceaa
7 changed files with 140 additions and 54 deletions

View file

@ -1696,15 +1696,15 @@ namespace events{
textbox_info_.show(gui::TEXTBOX_COMMAND,sgettext("prompt^Command:"), "", false, *gui_);
}
void menu_handler::change_side_controller(const std::string& side, const std::string& player, bool orphan_side)
void menu_handler::change_side_controller(const std::string& side, const std::string& player, bool own_side)
{
config cfg;
config& change = cfg.add_child("change_controller");
change["side"] = side;
change["player"] = player;
if(orphan_side) {
change["orphan_side"] = "yes";
if(own_side) {
change["own_side"] = "yes";
}
network::send_data(cfg);

View file

@ -120,7 +120,7 @@ private:
void write_game_snapshot(config& start) const;
bool has_friends() const;
bool clear_shroud(const unsigned int team_num);
void change_side_controller(const std::string& side, const std::string& player, bool orphan_side=false);
void change_side_controller(const std::string& side, const std::string& player, bool own_side=false);
display* gui_;
unit_map& units_;

View file

@ -199,7 +199,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
const size_t index = static_cast<size_t>(action - 3);
if (index < observers.size()) {
teams_[side].make_network();
change_side_controller(cfg["side_drop"], observers[index], true /*is orphaned side*/);
change_side_controller(cfg["side_drop"], observers[index], false /*not our own side*/);
} else {
teams_[side].make_ai();
}
@ -213,15 +213,15 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
return turn_end ? PROCESS_END_TURN : PROCESS_CONTINUE;
}
void turn_info::change_side_controller(const std::string& side, const std::string& player, bool orphan_side)
void turn_info::change_side_controller(const std::string& side, const std::string& player, bool own_side)
{
config cfg;
config& change = cfg.add_child("change_controller");
change["side"] = side;
change["player"] = player;
if(orphan_side) {
change["orphan_side"] = "yes";
if(own_side) {
change["own_side"] = "yes";
}
network::send_data(cfg);

View file

@ -57,7 +57,7 @@ public:
events::generic_event& replay_error() { return replay_error_; }
private:
void change_side_controller(const std::string& side, const std::string& player, bool orphan_side=false);
void change_side_controller(const std::string& side, const std::string& player, bool own_side=false);
const game_data& gameinfo_;
game_state& state_of_game_;

View file

@ -264,38 +264,30 @@ void game::update_side_data()
const std::string& game::transfer_side_control(const config& cfg)
{
bool observer_found = false;
bool player_found = false;
const std::string& player = cfg["player"];
user_vector users = all_game_users();
user_vector::iterator j;
for(j = users.begin(); j != users.end(); ++j) {
const player_map::const_iterator pl = player_info_->find(*j);
if(pl != player_info_->end() && pl->second.name() == player) {
//find the socket for the player that is passed control
network::connection sock_entering = NULL;
for (player_map::const_iterator pl = player_info_->begin(); pl != player_info_->end(); pl++){
if (pl->second.name() == player){
sock_entering = pl->first;
break;
}
}
user_vector::iterator i;
for(i = observers_.begin(); i != observers_.end(); ++i) {
const player_map::const_iterator pl = player_info_->find(*i);
if(pl != player_info_->end() && pl->second.name() == player) {
observer_found = true;
break;
}
}
player_found = !observer_found && j != users.end();
if(player_found) {
i = j;
}
if(!observer_found && !player_found) {
if (sock_entering == NULL){
static const std::string notfound = "Player/Observer not found";
return notfound;
}
user_vector::iterator i = find_in_observers(sock_entering);
user_vector::iterator j = find_in_players(sock_entering);
if (i == observers_.end() && j == players_.end()){
static const std::string notfound = "Player/Observer not found";
return notfound;
}
const std::string& side = cfg["side"];
static const std::string invalid = "Invalid side number";
size_t side_num;
@ -313,22 +305,69 @@ const std::string& game::transfer_side_control(const config& cfg)
const size_t side_index = static_cast<size_t>(side_num - 1);
if(side_controllers_[side_index] == "network" && sides_taken_[side_index]) {
if(side_controllers_[side_index] == "network" && sides_taken_[side_index] && cfg["own_side"] != "yes") {
static const std::string already = "This side is already controlled by a player";
return already;
}
if(cfg["orphan_side"] != "yes") {
const size_t active_side = end_turn_/nsides + 1;
if(lexical_cast_default<size_t>(side,0) == active_side) {
static const std::string not_during_turn = "You cannot change a side's controller during its turn";
return not_during_turn;
//The player owns this side
if(cfg["own_side"] == "yes") {
//get the socket of the player that issued the command
network::connection sock = NULL;
for (std::multimap<network::connection, size_t>::iterator s = sides_.begin(); s != sides_.end(); s++){
if (s->second == side_index){
sock = s->first;
break;
}
}
if (sock == NULL){
static const std::string player_not_found = "This side is not listed for the game";
return player_not_found;
}
//check, if this socket belongs to a player
user_vector::iterator p = find_in_players(sock);
if (p == players_.end()){
static const std::string no_player = "The player for this side could not be found";
return no_player;
}
//if this player controls only one side, make him an observer
if (sides_.count(sock) == 1){
//we need to save this information before the player is erased
bool host = is_needed(sock);
observers_.push_back(*p);
players_.erase(p);
//tell others that the player becomes an observer
config cfg_observer = construct_server_message(find_player(sock)->name() + " becomes observer");
send_data(cfg_observer);
//update the client observer list for everyone except player
config observer_join;
observer_join.add_child("observer").values["name"] = find_player(sock)->name();
send_data(observer_join, sock);
//if this player was the host of the game, transfer game control to another player
if (host && transfer_game_control() != NULL){
const config& msg = construct_server_message(transfer_game_control()->name() + " has been chosen as new host");
send_data(msg);
}
//reiterate because iterators became invalid
i = find_in_observers(sock_entering);
j = find_in_players(sock_entering);
}
//clear the sides_ entry
sides_.erase(s);
}
side_controllers_[side_index] = "network";
sides_taken_[side_index] = true;
sides_.insert(std::pair<const network::connection,size_t>(*i, side_index));
sides_.insert(std::pair<const network::connection,size_t>(sock_entering, side_index));
// send a response to the host and to the new controller
config response;
@ -340,17 +379,17 @@ const std::string& game::transfer_side_control(const config& cfg)
network::queue_data(response,players_.front());
change["controller"] = "human";
network::queue_data(response,*i);
network::queue_data(response, sock_entering);
if(sides_.count(*i) < 2) {
if(sides_.count(sock_entering) < 2) {
//send everyone a message saying that the observer who is taking the side has quit
config observer_quit;
observer_quit.add_child("observer_quit").values["name"] = player;
send_data(observer_quit);
}
if (observer_found){
observers_.erase(i);
if (i != observers_.end()){
players_.push_back(*i);
observers_.erase(i);
}
static const std::string success = "";
return success;
@ -798,3 +837,41 @@ const player* game::transfer_game_control(){
}
return result;
}
user_vector::iterator game::find_in_players(network::connection sock){
user_vector::iterator p;
for (p = players_.begin(); p != players_.end(); p++){
if ((*p) == sock){
return p;
}
}
return players_.end();
}
user_vector::iterator game::find_in_observers(network::connection sock){
user_vector::iterator o;
for (o = observers_.begin(); o != observers_.end(); o++){
if ((*o) == sock){
return o;
}
}
return observers_.end();
}
config game::construct_server_message(const std::string& message)
{
config turn;
if(started()) {
config& cmd = turn.add_child("turn");
config& cfg = cmd.add_child("command");
config& msg = cfg.add_child("speak");
msg["description"] = "server";
msg["message"] = message;
} else {
config& msg = turn.add_child("message");
msg["sender"] = "server";
msg["message"] = message;
}
return turn;
}

View file

@ -72,6 +72,7 @@ public:
int id() const;
config construct_server_message(const std::string& message);
void send_data(const config& data, network::connection exclude=0);
void send_data_team(const config& data, const std::string& team, network::connection exclude=0);
void send_data_observers(const config& data);
@ -121,6 +122,11 @@ public:
const player* transfer_game_control();
private:
//returns an iterator on the player_ vector if sock is found
user_vector::iterator find_in_players(network::connection sock);
//returns an iterator on the observer_ vector if sock is found
user_vector::iterator find_in_observers(network::connection sock);
//helps debugging player and observer lists
std::string debug_player_info() const;

View file

@ -859,18 +859,21 @@ void server::process_data_from_player_in_game(const network::connection sock, co
}
//if the owner is changing the controller for a side
if(g->is_owner(sock) && data.child("change_controller") != NULL) {
if (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);
}
//the player is either host of the game or gives away his own side
if(g->is_owner(sock) || change["own_side"] == "yes") {
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;
return;
}
}
//if all observers are muted