fix bug #18829
it turns out that when the "network_ai" controller type was introduced, it was implemented on the server in the following way:a4f47a63c7/src/server/game.cpp (L464)
change_controller requests to the type "ai" are always transformed by the server into either "human_ai" for host or "network_ai" for client, and in thunderstruck's refactor of the mp_connect dialogs, ai sides are always set to "ai" in the WML sent to the server (and set this way on the host). however, because of code in play_campaign.cpp which long predated this refactor, all sides on an mp client are either set to human (if that player controls them) or "network", or "null". this causes problems because if that player saves the game, the savegame will record these sides at human controlled rather than ai controlled... if the game is reloaded oos can occur, although I won't detail it here. we update the play_campaign.cpp code to ensure that "ai" controller types always resolve to human_ai or network_ai as appropriate. additionally, we make sure that on the host, sides always resolve to human_ai rather than ai. so the type "ai" should never be observed during an mp game, and only during scenario configuration, and perhaps during replays. additionally, we ensure in playturn.cpp that if the client gets a message from the server to set a side to "ai" during the game, it will in fact set it to "human_ai" or "network_ai", to preserve the invariant. finally we also switch over observers to follow this behavior -- previously there was a hack here in the server which would make sure that any observers which join see all sides as controlled by "human"a4f47a63c7/src/server/game.cpp (L197)
in order that they do not attempt to substitute themselves for a player. we change this by removing the hack, and programming the client to remember if the player is an observer, and if so not attempting to substitute themself at game start.
This commit is contained in:
parent
886c2390d8
commit
736ceaa6c7
6 changed files with 40 additions and 9 deletions
|
@ -29,6 +29,10 @@ Version 1.13.0-dev:
|
|||
* Increased the sound mixer channel allocation from 16 to 32, thereby
|
||||
raising the limit for simultaneous sound effects from 5 to 21.
|
||||
* Fix bug #21758: "Ready not blocked while player pick faction."
|
||||
* Fix bug #18829: "ai sides show up as "controller=network" on remote clients".
|
||||
This issue is the source of some difficulties with mp campaigns which occur
|
||||
when the campaign is reloaded from a non-host side, or after a player rejoins
|
||||
from observer status. Hopefully, reloading campaigns is easier after this.
|
||||
|
||||
Version 1.11.11:
|
||||
* Add-ons server:
|
||||
|
|
|
@ -459,7 +459,7 @@ static void enter_wait_mode(game_display& disp, const config& game_config,
|
|||
switch (res) {
|
||||
case mp::ui::PLAY:
|
||||
play_game(disp, state, game_config, IO_CLIENT,
|
||||
preferences::skip_mp_replay() && observe, true, preferences::blindfold_replay() && observe);
|
||||
preferences::skip_mp_replay() && observe, true, preferences::blindfold_replay() && observe, observe);
|
||||
recorder.clear();
|
||||
|
||||
break;
|
||||
|
|
|
@ -365,7 +365,7 @@ static LEVEL_RESULT playmp_scenario(const config& game_config,
|
|||
|
||||
LEVEL_RESULT play_game(game_display& disp, game_state& gamestate,
|
||||
const config& game_config, io_type_t io_type, bool skip_replay,
|
||||
bool network_game, bool blindfold_replay)
|
||||
bool network_game, bool blindfold_replay, bool observer)
|
||||
{
|
||||
std::string type = gamestate.classification().campaign_type;
|
||||
if(type.empty())
|
||||
|
@ -428,7 +428,9 @@ LEVEL_RESULT play_game(game_display& disp, game_state& gamestate,
|
|||
|
||||
while(scenario != NULL) {
|
||||
// If we are a multiplayer client, tweak the controllers
|
||||
LOG_RG << "*** Playcampaign.cpp: Tweaking controllers ***" << std::endl;
|
||||
if(io_type == IO_CLIENT) {
|
||||
LOG_RG << "*** Playcampaign.cpp: We are a IO_CLIENT ***" << std::endl;
|
||||
if(scenario != &starting_pos) {
|
||||
starting_pos = *scenario;
|
||||
scenario = &starting_pos;
|
||||
|
@ -436,11 +438,27 @@ LEVEL_RESULT play_game(game_display& disp, game_state& gamestate,
|
|||
|
||||
BOOST_FOREACH(config &side, starting_pos.child_range("side"))
|
||||
{
|
||||
if (side["current_player"] == preferences::login()) {
|
||||
LOG_RG << "*** Playcampaign.cpp: Tweaked " << side["controller"] << " -> " << std::endl;
|
||||
if (!observer && side["current_player"] == preferences::login()) {//if we are not an observer and we are this player, it is our side
|
||||
side["controller"] = "human";
|
||||
} else if (side["controller"] != "null") {
|
||||
side["controller"] = "network";
|
||||
}
|
||||
} else if (side["controller"] == "ai" || side["controller"] == "human_ai" || side["controller"] == "network_ai") {
|
||||
side["controller"] = "network_ai"; //if server sends an ai side at start of scenario, it
|
||||
} else if (side["controller"] != "null") { //is owned by the host (and definitely not us)
|
||||
side["controller"] = "network"; //otherwise, side is controlled by human-host or null
|
||||
} //and shold be networked, null resp.
|
||||
//(did we miss anything?)
|
||||
LOG_RG << "\t\t\t\t\t" << side["controller"] << std::endl;
|
||||
}
|
||||
} else if (io_type == IO_SERVER)
|
||||
{
|
||||
LOG_RG << "*** Playcampaign.cpp: We are a IO_SERVER ***" << std::endl;
|
||||
BOOST_FOREACH(config &side, starting_pos.child_range("side"))
|
||||
{
|
||||
LOG_RG << "*** Playcampaign.cpp: Tweaked " << side["controller"] << " -> " << std::endl;
|
||||
if (side["controller"] == "ai") {
|
||||
side["controller"] = "human_ai"; //this is to guarantee that in an actual mp game, all ai sides will be "human_ai"
|
||||
} //or "network_ai", and "ai" only occurs during configuration.
|
||||
LOG_RG << "\t\t\t\t\t" << side["controller"] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@ LEVEL_RESULT play_game(game_display& disp, game_state& state,
|
|||
io_type_t io_type=IO_NONE,
|
||||
bool skip_replay = false,
|
||||
bool network_game = false,
|
||||
bool blindfold_replay = false);
|
||||
bool blindfold_replay = false,
|
||||
bool observer = false);
|
||||
|
||||
void play_replay(display& disp, game_state& state,
|
||||
const config& game_config, CVideo& video);
|
||||
|
|
|
@ -191,7 +191,13 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
} else if (controller == "network_ai" && !tm.is_network_ai()) {
|
||||
tm.make_network_ai();
|
||||
} else if (controller == "ai" && !tm.is_ai()) {
|
||||
tm.make_ai();
|
||||
//if we are the controller, this should become human_ai, if not then network_ai
|
||||
//this is to ensure that no side during an mp game is ever "ai", and always either human_ai or network_ai (except during configuration)
|
||||
if (player == preferences::login()) {
|
||||
tm.make_human_ai();
|
||||
} else {
|
||||
tm.make_network_ai();
|
||||
}
|
||||
} else if (controller == "idle" && !tm.is_idle()) {
|
||||
tm.make_idle();
|
||||
}
|
||||
|
|
|
@ -183,6 +183,8 @@ void game::start_game(const player_map::const_iterator starter) {
|
|||
// Set all side controllers to 'human' so that observers will understand
|
||||
// that they can't take control of any sides if they happen to have the
|
||||
// same name as one of the descriptions.
|
||||
// iceiceice 3/17/2014: disabled this behavior as it causes out of sync
|
||||
// the observer issue is now handled by ... client remembers if they are observing.
|
||||
const simple_wml::node::child_list& sides = level_.root().children("side");
|
||||
for(simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
|
||||
nsides_++;
|
||||
|
@ -194,7 +196,7 @@ void game::start_game(const player_map::const_iterator starter) {
|
|||
LOG_GAME << msg.str() << " (game id: " << id_ << ")\n";
|
||||
send_and_record_server_message(msg.str());
|
||||
}
|
||||
(*s)->set_attr("controller", "human");
|
||||
//(*s)->set_attr("controller", "human");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue