replace controller=network,network_ai with is_local=no in [side]
This has 3 advantages: 1) It makes the serversided handling of controller= attribute easier. 2) It prevents OOS causes by wrong use of the [side] controller= attribute 3) It gived us a field to store the local/remote data for null-controlled sides, this could be useful in cases where the controller changes from null no non-null, Currently is_local is ignored for null-controlled sides.
This commit is contained in:
parent
12b72bfa90
commit
4d14482159
8 changed files with 48 additions and 93 deletions
|
@ -212,13 +212,13 @@ void game_board::side_drop_to(int side_num, team::CONTROLLER ctrl, team::PROXY_C
|
|||
if (leader.valid()) leader->rename(lexical_cast<std::string> (ctrl) + lexical_cast<std::string> (side_num));
|
||||
}
|
||||
|
||||
void game_board::side_change_controller(int side_num, team::CONTROLLER ctrl, const std::string& pname) {
|
||||
void game_board::side_change_controller(int side_num, bool is_local, const std::string& pname) {
|
||||
team &tm = teams_[side_num-1];
|
||||
|
||||
tm.change_controller(ctrl);
|
||||
tm.set_local(is_local);
|
||||
|
||||
if (pname.empty()) {
|
||||
return ;
|
||||
if (pname.empty() || !tm.is_human()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tm.set_current_player(pname);
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
// Manipulator from playturn
|
||||
|
||||
void side_drop_to (int side_num, team::CONTROLLER ctrl, team::PROXY_CONTROLLER proxy = team::PROXY_CONTROLLER::PROXY_HUMAN);
|
||||
void side_change_controller (int side_num, team::CONTROLLER ctrl, const std::string& pname = "");
|
||||
void side_change_controller (int side_num, bool is_local, const std::string& pname = "");
|
||||
|
||||
// Manipulator from actionwml
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ static lg::log_domain log_network("network");
|
|||
namespace {
|
||||
|
||||
const std::string controller_names[] = {
|
||||
"network",
|
||||
"human",
|
||||
"human",
|
||||
"ai",
|
||||
"null",
|
||||
|
@ -1011,12 +1011,10 @@ config side_engine::new_config() const
|
|||
}
|
||||
|
||||
res["controller"] = controller_names[controller_];
|
||||
if(player_id_ == preferences::login() && res["controller"] == "network") {
|
||||
// the hosts rveices the serversided controller wteaks after the start event, but
|
||||
// for mp sync it's very important that the controller types are correct
|
||||
// during the start/prestart event (otherwse random unit creation during prestart fails).
|
||||
res["controller"] = "human";
|
||||
}
|
||||
// the hosts rveices the serversided controller tweaks after the start event, but
|
||||
// for mp sync it's very important that the controller types are correct
|
||||
// during the start/prestart event (otherwse random unit creation during prestart fails).
|
||||
res["is_local"] = player_id_ == preferences::login();
|
||||
|
||||
std::string desc = user_description();
|
||||
if(!desc.empty()) {
|
||||
|
|
|
@ -279,7 +279,7 @@ void wait::join_game(bool observe)
|
|||
side_num = nb_sides;
|
||||
break;
|
||||
}
|
||||
if (sd["controller"] == "network" && sd["player_id"].empty())
|
||||
if (sd["controller"] == "human" && sd["player_id"].empty())
|
||||
{
|
||||
if (!side_choice) { // found the first empty side
|
||||
side_choice = &sd;
|
||||
|
|
|
@ -173,30 +173,20 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
ERR_NW << "Bad [change_controller] signal from server, [change_controller] tag was empty." << std::endl;
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
//don't use lexical_cast_default it's "safer" to end on error
|
||||
const int side = lexical_cast<int>(change["side"]);
|
||||
|
||||
const int side = change["side"].to_int();
|
||||
const bool is_local = change["is_local"].to_bool();
|
||||
const std::string player = change["player"];
|
||||
const size_t index = side - 1;
|
||||
|
||||
assert(resources::gameboard);
|
||||
|
||||
if(index >= resources::gameboard->teams().size()) {
|
||||
ERR_NW << "Bad [change_controller] signal from server, side out of bounds: " << change.debug() << std::endl;
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
const team & tm = resources::gameboard->teams().at(index);
|
||||
const std::string &player = change["player"];
|
||||
const bool was_local = tm.is_local();
|
||||
|
||||
team::CONTROLLER new_controller = team::CONTROLLER();
|
||||
try {
|
||||
new_controller = team::CONTROLLER::string_to_enum(change["controller"].str());
|
||||
} catch (bad_enum_cast & e) {
|
||||
ERR_NW << "Bad [change_controller] message from server:\n" << e.what() << std::endl << change.debug() << std::endl;
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
resources::gameboard->side_change_controller(side, new_controller, player);
|
||||
resources::gameboard->side_change_controller(side, is_local, player);
|
||||
|
||||
if (!was_local && tm.is_local()) {
|
||||
resources::controller->on_not_observer();
|
||||
|
|
|
@ -245,12 +245,8 @@ void game::perform_controller_tweaks() {
|
|||
// Therefore, if the side belongs to the host, we pass player_left = true, otherwise player_left = false.
|
||||
change_controller(side_index, sides_[side_index], user_name , sides_[side_index] == owner_);
|
||||
|
||||
//next lines change controller types found in level_ to be what is appropriate for an observer at game start.
|
||||
if ((**s)["controller"] == "ai") {
|
||||
(*s)->set_attr("controller", "network_ai");
|
||||
} else { //this catches "reserved" also
|
||||
(*s)->set_attr("controller", "network");
|
||||
}
|
||||
//next line change controller types found in level_ to be what is appropriate for an observer at game start.
|
||||
(*s)->set_attr("is_local", "no");
|
||||
|
||||
if (sides_[side_index] == 0) {
|
||||
std::stringstream msg;
|
||||
|
@ -366,10 +362,12 @@ bool game::take_side(const player_map::const_iterator user)
|
|||
simple_wml::document cfg;
|
||||
cfg.root().set_attr_dup("name", user->second.name().c_str());
|
||||
|
||||
//FIXME: It the client code (multiplayer.wait.cpp) the host code (connect_engine.cpp) and the server code (this file)
|
||||
// Has this code to figure out a fitting aise for a new players, tis is clearly too much.
|
||||
// Check if we can figure out a fitting side.
|
||||
const simple_wml::node::child_list& sides = get_sides_list();
|
||||
for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
|
||||
if(((**side)["controller"] == "network" || (**side)["controller"] == "reserved")
|
||||
if(((**side)["controller"] == "human" || (**side)["controller"] == "reserved")
|
||||
&& (**side)["current_player"] == user->second.name().c_str())
|
||||
{
|
||||
if (send_taken_side(cfg, side)) return true;
|
||||
|
@ -377,7 +375,7 @@ bool game::take_side(const player_map::const_iterator user)
|
|||
}
|
||||
// If there was no fitting side just take the first available.
|
||||
for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
|
||||
if((**side)["controller"] == "network") {
|
||||
if((**side)["controller"] == "human") {
|
||||
if (send_taken_side(cfg, side)) return true;
|
||||
}
|
||||
}
|
||||
|
@ -433,14 +431,11 @@ void game::update_side_data()
|
|||
const simple_wml::string_span& player_id = (**side)["player_id"];
|
||||
const simple_wml::string_span& controller = (**side)["controller"];
|
||||
if ( player_id == info->second.name().c_str()) {
|
||||
//if this is called before perform_controller_tweaks() we have "ai" and "human" controllers
|
||||
//if its called after that we have "network" and "network_ai" controllers.
|
||||
if(controller != "network" && controller != "human" && controller != "ai" && controller != "network_ai") {
|
||||
if(controller != "human" && controller != "ai") {
|
||||
//we found invalid [side] data. Some message would be cool.
|
||||
continue;
|
||||
}
|
||||
//convert "network_ai" -> "ai", "network" -> "human"
|
||||
side_controllers_[side_index] = controller == "network" ? "human" : controller == "network_ai" ? "ai" : controller.to_string();
|
||||
side_controllers_[side_index] = controller.to_string();
|
||||
sides_[side_index] = *user;
|
||||
side_found = true;
|
||||
}
|
||||
|
@ -573,7 +568,8 @@ void game::change_controller(const size_t side_index,
|
|||
change.set_attr("player", player_name.c_str());
|
||||
|
||||
// Tell everyone but the new player that this side's controller changed.
|
||||
change.set_attr("controller", (side_controllers_[side_index] == "ai" ? "network_ai" : "network"));
|
||||
change.set_attr("controller", (side_controllers_[side_index] == "ai" ? "ai" : "human"));
|
||||
change.set_attr("is_local", "no");
|
||||
|
||||
send_data(response, sock);
|
||||
if (started_) { //this is added instead of the if (started_) {...} below
|
||||
|
@ -585,7 +581,7 @@ void game::change_controller(const size_t side_index,
|
|||
// Just don't send it when the player left the game. (The host gets the
|
||||
// side_drop already.)
|
||||
if (!player_left) {
|
||||
change.set_attr("controller", (side_controllers_[side_index] == "ai" ? "ai" : "human"));
|
||||
change.set_attr("is_local", "yes");
|
||||
wesnothd::send_to_one(response, sock);
|
||||
}
|
||||
}
|
||||
|
@ -1047,18 +1043,14 @@ void game::handle_controller_choice(const simple_wml::node& req)
|
|||
simple_wml::node& command = turn.add_child("command");
|
||||
simple_wml::node& change_controller_wml = command.add_child("change_controller_wml");
|
||||
change_controller_wml.set_attr_dup("controller", new_controller.c_str());
|
||||
change_controller_wml.set_attr_dup("is_local", "yes");
|
||||
command.set_attr("from_side", "server");
|
||||
command.set_attr("dependent", "yes");
|
||||
if(sides_[side_index] != 0) {
|
||||
//calling send_to_one to 0 connect causes the package to be sended to all clients.
|
||||
wesnothd::send_to_one(*mdata, sides_[side_index], "game replay");
|
||||
}
|
||||
if(new_controller == "human") {
|
||||
change_controller_wml.set_attr("controller", "network");
|
||||
}
|
||||
if(new_controller == "ai") {
|
||||
change_controller_wml.set_attr("controller", "network_ai");
|
||||
}
|
||||
change_controller_wml.set_attr_dup("is_local", "no");
|
||||
send_data(*mdata, sides_[side_index], "game replay");
|
||||
record_data(mdata);
|
||||
}
|
||||
|
@ -1391,27 +1383,9 @@ void game::load_next_scenario(const player_map::const_iterator user) {
|
|||
LOG_GAME << msg.str() << " (game id: " << id_ << ")\n";
|
||||
send_and_record_server_message(msg.str());
|
||||
} else if (sides_[side_index] == user->first) {
|
||||
if (side_controllers_[side_index] == "human") {
|
||||
(*s)->set_attr("controller", "human");
|
||||
} else if (side_controllers_[side_index] == "ai") {
|
||||
(*s)->set_attr("controller", "ai");
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "Side " << side_index + 1 << " had unexpected side_controller = " << side_controllers_[side_index] << " on server side.";
|
||||
LOG_GAME << msg.str() << " (game id: " << id_ << ")\n";
|
||||
send_and_record_server_message(msg.str());
|
||||
}
|
||||
(*s)->set_attr("is_local", "yes");
|
||||
} else {
|
||||
if (side_controllers_[side_index] == "human") {
|
||||
(*s)->set_attr("controller", "network");
|
||||
} else if (side_controllers_[side_index] == "ai") {
|
||||
(*s)->set_attr("controller", "network_ai");
|
||||
} else {
|
||||
std::stringstream msg;
|
||||
msg << "Side " << side_index + 1 << " had unexpected side_controller = " << side_controllers_[side_index] << " on server side.";
|
||||
LOG_GAME << msg.str() << " (game id: " << id_ << ")\n";
|
||||
send_and_record_server_message(msg.str());
|
||||
}
|
||||
(*s)->set_attr("is_local", "no");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
src/team.cpp
20
src/team.cpp
|
@ -96,6 +96,7 @@ team::team_info::team_info() :
|
|||
objectives(),
|
||||
objectives_changed(false),
|
||||
controller(),
|
||||
is_local(true),
|
||||
defeat_condition(team::DEFEAT_CONDITION::NO_LEADER),
|
||||
proxy_controller(team::PROXY_CONTROLLER::PROXY_HUMAN),
|
||||
share_vision(team::SHARE_VISION::ALL),
|
||||
|
@ -146,6 +147,7 @@ void team::team_info::read(const config &cfg)
|
|||
carryover_bonus = cfg["carryover_bonus"].to_double(1);
|
||||
carryover_gold = cfg["carryover_gold"].to_int(0);
|
||||
variables = cfg.child_or_empty("variables");
|
||||
is_local = cfg["is_local"].to_bool(true);
|
||||
|
||||
if(cfg.has_attribute("color")) {
|
||||
color = cfg["color"].str();
|
||||
|
@ -204,7 +206,7 @@ void team::team_info::read(const config &cfg)
|
|||
}
|
||||
//override persistence flag if it is explicitly defined in the config
|
||||
//by default, persistence of a team is set depending on the controller
|
||||
persistent = cfg["persistent"].to_bool(this->controller == CONTROLLER::HUMAN || this->controller == CONTROLLER::NETWORK);
|
||||
persistent = cfg["persistent"].to_bool(this->controller == CONTROLLER::HUMAN);
|
||||
|
||||
//========================================================
|
||||
//END OF MESSY CODE
|
||||
|
@ -475,14 +477,6 @@ bool team::calculate_is_enemy(size_t index) const
|
|||
|
||||
namespace
|
||||
{
|
||||
team::CONTROLLER unified_controller(team::CONTROLLER c)
|
||||
{
|
||||
if(c == team::CONTROLLER::NETWORK)
|
||||
return team::CONTROLLER::HUMAN;
|
||||
if(c == team::CONTROLLER::NETWORK_AI)
|
||||
return team::CONTROLLER::AI;
|
||||
return c;
|
||||
}
|
||||
class controller_server_choice : public synced_context::server_choice
|
||||
{
|
||||
public:
|
||||
|
@ -501,7 +495,7 @@ namespace
|
|||
{
|
||||
return config_of
|
||||
("new_controller", new_controller_)
|
||||
("old_controller", unified_controller(team_.controller()))
|
||||
("old_controller", team_.controller())
|
||||
("side", team_.side());
|
||||
}
|
||||
virtual const char* name() const
|
||||
|
@ -519,17 +513,15 @@ void team::change_controller_by_wml(const std::string& new_controller_string)
|
|||
try
|
||||
{
|
||||
CONTROLLER new_controller = lexical_cast<CONTROLLER> (new_controller_string);
|
||||
if(new_controller == CONTROLLER::NETWORK || new_controller == CONTROLLER::NETWORK_AI) {
|
||||
throw bad_enum_cast(new_controller_string, "CONTROLLER"); //catched below
|
||||
}
|
||||
if(new_controller == CONTROLLER::EMPTY && resources::controller->current_side() == this->side()) {
|
||||
//We dont allow changing the currently active side to "null" controlled.
|
||||
//We don't allow changing the currently active side to "null" controlled.
|
||||
throw bad_enum_cast(new_controller_string, "CONTROLLER"); //catched below
|
||||
}
|
||||
config choice = synced_context::ask_server_choice(controller_server_choice(new_controller, *this));
|
||||
if(!new_controller.parse(choice["controller"])) {
|
||||
ERR_NG << "recieved an invalid controller string from the server" << choice["controller"] << std::endl;
|
||||
}
|
||||
set_local(choice["is_local"].to_bool());
|
||||
change_controller(new_controller);
|
||||
}
|
||||
catch(const bad_enum_cast&)
|
||||
|
|
21
src/team.hpp
21
src/team.hpp
|
@ -55,8 +55,6 @@ public:
|
|||
MAKE_ENUM(CONTROLLER,
|
||||
(HUMAN, "human")
|
||||
(AI, "ai")
|
||||
(NETWORK, "network")
|
||||
(NETWORK_AI, "network_ai")
|
||||
(EMPTY, "null")
|
||||
)
|
||||
|
||||
|
@ -140,6 +138,7 @@ private:
|
|||
mutable bool objectives_changed;
|
||||
|
||||
CONTROLLER controller;
|
||||
bool is_local;
|
||||
DEFEAT_CONDITION defeat_condition;
|
||||
|
||||
PROXY_CONTROLLER proxy_controller; // when controller == HUMAN, the proxy controller determines what input method is actually used.
|
||||
|
@ -257,24 +256,26 @@ public:
|
|||
void set_color(const std::string& color) { info_.color = color; }
|
||||
bool is_empty() const { return info_.controller == CONTROLLER::EMPTY; }
|
||||
|
||||
bool is_local() const { return is_local_human() || is_local_ai(); }
|
||||
bool is_network() const { return is_network_human() || is_network_ai(); }
|
||||
bool is_local() const { return !is_empty() && info_.is_local; }
|
||||
bool is_network() const { return !is_empty() && !info_.is_local; }
|
||||
|
||||
bool is_human() const { return is_local_human() || is_network_human(); }
|
||||
bool is_human() const { return info_.controller == CONTROLLER::HUMAN; }
|
||||
bool is_ai() const { return info_.controller == CONTROLLER::AI; }
|
||||
|
||||
bool is_local_human() const { return info_.controller == CONTROLLER::HUMAN; }
|
||||
bool is_local_ai() const { return info_.controller == CONTROLLER::AI; }
|
||||
bool is_network_human() const { return info_.controller == CONTROLLER::NETWORK; }
|
||||
bool is_network_ai() const { return info_.controller == CONTROLLER::NETWORK_AI; }
|
||||
bool is_local_human() const { return is_human() && is_local(); }
|
||||
bool is_local_ai() const { return is_ai() && is_local(); }
|
||||
bool is_network_human() const { return is_human() && is_network(); }
|
||||
bool is_network_ai() const { return is_ai() && is_network(); }
|
||||
|
||||
void set_local(bool local) { info_.is_local = local; }
|
||||
void make_human() { info_.controller = CONTROLLER::HUMAN; }
|
||||
void make_ai() { info_.controller = CONTROLLER::AI; }
|
||||
void change_controller(const std::string& new_controller) {
|
||||
info_.controller = CONTROLLER::AI;
|
||||
info_.controller.parse(new_controller);
|
||||
}
|
||||
void change_controller_by_wml(const std::string& new_controller);
|
||||
void change_controller(CONTROLLER controller) { info_.controller = controller; }
|
||||
void change_controller_by_wml(const std::string& new_controller);
|
||||
|
||||
PROXY_CONTROLLER proxy_controller() const { return info_.proxy_controller; }
|
||||
bool is_proxy_human() const { return info_.proxy_controller == PROXY_CONTROLLER::PROXY_HUMAN; }
|
||||
|
|
Loading…
Add table
Reference in a new issue