diff --git a/src/play_controller.cpp b/src/play_controller.cpp index 95953472bb1..bd908eef8e1 100644 --- a/src/play_controller.cpp +++ b/src/play_controller.cpp @@ -42,7 +42,9 @@ #include "save_blocker.hpp" #include "preferences_display.hpp" #include "replay.hpp" +#include "random_new_deterministic.hpp" #include "soundsource.hpp" +#include "synced_context.hpp" #include "tooltips.hpp" #include "wml_exception.hpp" #include "ai/manager.hpp" @@ -174,13 +176,8 @@ void play_controller::init(CVideo& video){ } loadscreen::start_stage("load level"); - // If the recorder has no event, adds an "game start" event - // to the recorder, whose only goal is to initialize the RNG - if(recorder.empty()) { - recorder.add_start(); - } else { - recorder.pre_replay(); - } + // i currently assume that no random calls take place before the "prestart" event + // If i am wrong, use random_new_deterministic recorder.set_skip(false); bool snapshot = level_["snapshot"].to_bool(); @@ -545,14 +542,16 @@ void play_controller::search(){ menu_handler_.search(); } -void play_controller::fire_prestart(bool execute) +void play_controller::fire_preload() { // Run initialization scripts, even if loading from a snapshot. gamedata_.set_phase(game_data::PRELOAD); resources::lua_kernel->initialize(); gamedata_.get_variable("turn_number") = int(turn()); game_events::fire("preload"); - +} +void play_controller::fire_prestart(bool execute) +{ // pre-start events must be executed before any GUI operation, // as those may cause the display to be refreshed. if (execute){ @@ -622,8 +621,11 @@ void play_controller::maybe_do_init_side(const unsigned int team_index, bool is_ } if (!loading_game_) recorder.init_side(); - + LOG_NG << "set_scontext_synced sync from maybe_do_init_side"; + set_scontext_synced sync; do_init_side(team_index, is_replay); + LOG_NG << "set_scontext_synced sync from maybe_do_init_side end "; + } /** @@ -787,11 +789,15 @@ void play_controller::finish_side_turn(){ const std::string turn_num = str_cast(turn()); const std::string side_num = str_cast(player_number_); + if(true) //RAII block + { + set_scontext_synced sync(1); + //random_new::set_random_determinstic deterministic(resources::gamedata->rng()); game_events::fire("side turn end"); game_events::fire("side "+ side_num + " turn end"); game_events::fire("side turn " + turn_num + " end"); game_events::fire("side " + side_num + " turn " + turn_num + " end"); - + } // This is where we refog, after all of a side's events are done. actions::recalculate_fog(player_number_); @@ -809,6 +815,8 @@ void play_controller::finish_side_turn(){ void play_controller::finish_turn() { + set_scontext_synced sync(2); + //random_new::set_random_determinstic deterministic(resources::gamedata->rng()); const std::string turn_num = str_cast(turn()); game_events::fire("turn end"); game_events::fire("turn " + turn_num + " end"); diff --git a/src/play_controller.hpp b/src/play_controller.hpp index 975bda4f53f..72646fab73e 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -189,6 +189,8 @@ protected: bool in_context_menu(hotkey::HOTKEY_COMMAND command) const; void init_managers(); + ///preload events cannot be synced + void fire_preload(); void fire_prestart(bool execute); void fire_start(bool execute); virtual void init_gui(); diff --git a/src/playsingle_controller.cpp b/src/playsingle_controller.cpp index 71abfdbfe66..df997c13ee4 100644 --- a/src/playsingle_controller.cpp +++ b/src/playsingle_controller.cpp @@ -35,8 +35,11 @@ #include "marked-up_text.hpp" #include "playturn.hpp" #include "resources.hpp" +#include "random_new_deterministic.hpp" +#include "replay_helper.hpp" #include "savegame.hpp" #include "sound.hpp" +#include "synced_context.hpp" #include "formula_string_utils.hpp" #include "events.hpp" #include "save_blocker.hpp" @@ -371,20 +374,48 @@ LEVEL_RESULT playsingle_controller::play_scenario( gamestate_.replay_start() = to_config(); gamestate_.write_snapshot(gamestate_.replay_start(), gui_.get()); } - - fire_prestart(!loading_game_); - init_gui(); - - past_prestart = true; - - LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; - - events::raise_draw_event(); - fire_start(!loading_game_); - gui_->recalculate_minimap(); - + fire_preload(); + replaying_ = (recorder.at_end() == false); + if(!loading_game_ ) + { + if(replaying_) + { + //can this codepath be reached ? + //note this when we are entering an mp game and see the 'replay' of the game + //this path is not reached because we receive the replay later + config* pstart = recorder.get_next_action(); + assert(pstart->has_child("start")); + } + else + { + assert(recorder.empty()); + recorder.add_start(); + recorder.get_next_action(); + } + //we can only use a set_scontext_synced with a non empty recorder. + set_scontext_synced sync; + + fire_prestart(true); + init_gui(); + past_prestart = true; + LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; + + events::raise_draw_event(); + fire_start(true); + gui_->recalculate_minimap(); + } + else + { + init_gui(); + past_prestart = true; + events::raise_draw_event(); + fire_start(false); + gui_->recalculate_minimap(); + } + + LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. @@ -891,8 +922,7 @@ void playsingle_controller::play_ai_turn(){ if ( !cur_team.auto_shroud_updates() ) { // We just took control, so the undo stack is empty. We still need // to record this change for the replay though. - recorder.add_auto_shroud(true); - cur_team.set_auto_shroud_updates(true); + synced_context::run_in_synced_context("auto_shroud", replay_helper::get_auto_shroud(true)); } turn_info turn_data(player_number_, replay_sender_); diff --git a/src/playsingle_controller.hpp b/src/playsingle_controller.hpp index ccb11e48814..3df08726872 100644 --- a/src/playsingle_controller.hpp +++ b/src/playsingle_controller.hpp @@ -94,6 +94,7 @@ protected: const cursor::setter cursor_setter; std::deque data_backlog_; gui::floating_textbox textbox_info_; + replay_network_sender replay_sender_; bool end_turn_; diff --git a/src/replay_controller.cpp b/src/replay_controller.cpp index b123eac4bee..715c48cc97d 100644 --- a/src/replay_controller.cpp +++ b/src/replay_controller.cpp @@ -22,9 +22,11 @@ #include "log.hpp" #include "map_label.hpp" #include "replay.hpp" +#include "random_new_deterministic.hpp" #include "replay_controller.hpp" #include "resources.hpp" #include "savegame.hpp" +#include "synced_context.hpp" #include @@ -286,9 +288,28 @@ void replay_controller::reset_replay(){ } // Scenario initialization. (c.f. playsingle_controller::play_scenario()) - fire_prestart(true); - init_gui(); - fire_start(true); + fire_preload(); + if(true){ + config* pstart = recorder.get_next_action(); + assert(pstart->has_child("start")); + /* + use this after recorder.add_synced_command + because set_scontext_synced sets the checkup to the last added command + */ + set_scontext_synced sync; + + + //block for RAII + // if we use set_scontext_synced we need to have fire_prestart and fire_start in the same set_scontext_synced block because + // we can only have one set_scontext_synced per replay command (here it is the "start" replay command). + // and there is no replay command between them. + // EDIT: if the server dont allow require_random form other sides this comment is outdated. + DBG_REPLAY << "set_random_determinstic sync in replay_controller::reset_replay()\n"; + fire_prestart(true); + init_gui(); + fire_start(true); + DBG_REPLAY << "set_scontext_synced sync in replay_controller::reset_replay() end\n"; + } // Since we did not fire the start event, it_is_a_new_turn_ has the wrong value. it_is_a_new_turn_ = true; update_gui();