42 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
43 #define LOG_REPLAY LOG_STREAM(info, log_replay)
44 #define WRN_REPLAY LOG_STREAM(warn, log_replay)
45 #define ERR_REPLAY LOG_STREAM(err, log_replay)
49 DBG_REPLAY <<
"run_in_synced_context:" << commandname;
57 spectator.
error(
"commandname [" + commandname +
"] not found");
59 bool success = it->second(
data, spectator);
85 ERR_REPLAY <<
"ignored attempt to invoke a synced command during replay";
91 bool success =
run(commandname,
data, spectator);
117 ERR_REPLAY <<
"trying to execute action while being in a local_choice";
125 spectator.
error(
"commandname [" + commandname +
"] not found");
128 return it->second(
data, spectator);
132 assert(
false &&
"found unknown synced_context::synced_state");
142 void error(
const std::string& message)
144 ERR_REPLAY <<
"Unexpected Error during synced execution" << message;
145 assert(!
"Unexpected Error during synced execution, more info in stderr.");
169 virtual const char*
name()
const override
171 return "random_seed";
181 return seed_val.
str();
235 if(mode ==
"deterministic" || mode ==
"biased") {
236 auto get_rng = []() {
241 return std::make_shared<randomness::rng_proxy>(get_rng);
255 "request_choice",
config {
256 "request_id", request_id(),
266 <<
"' choice in a unsynced context, doing the choice locally. This can cause OOS.";
273 bool did_require =
false;
282 if(is_replay_end && !is_mp_game) {
284 DBG_REPLAY <<
"MP synchronization: local server choice";
292 }
else if(is_replay_end && is_mp_game) {
293 DBG_REPLAY <<
"MP synchronization: remote server choice";
308 using namespace std::chrono_literals;
309 std::this_thread::sleep_for(10ms);
312 }
else if(!is_replay_end) {
314 DBG_REPLAY <<
"MP synchronization: replay server choice";
326 + action->
debug() +
"\n");
332 if((*action)[
"from_side"].str() !=
"server" || (*action)[
"side_invalid"].to_bool(
false)) {
339 if(res[
"request_id"].to_int() != sch.
request_id()) {
340 WRN_REPLAY <<
"Unexpected request_id: " << res[
"request_id"] <<
" expected: " << sch.
request_id();
366 return ct.
is_ai() && ct.auto_shroud_updates();
373 LOG_REPLAY <<
"set_scontext_synced_base::set_scontext_synced_base";
389 LOG_REPLAY <<
"set_scontext_synced_base:: destructor";
397 , new_checkup_(generate_checkup(
"checkup"))
405 , new_checkup_(generate_checkup(
"checkup" + std::to_string(number)))
425 LOG_REPLAY <<
"set_scontext_synced::set_scontext_synced";
434 std::stringstream
msg;
437 "random_calls",
new_rng_->get_random_calls(),
445 if(co[
"random_calls"].empty()) {
446 msg <<
"cannot find random_calls check in replay" << std::endl;
447 }
else if(co[
"random_calls"] != cn[
"random_calls"]) {
448 msg <<
"We called random " <<
new_rng_->get_random_calls() <<
" times, but the original game called random "
449 << co[
"random_calls"].to_int() <<
" times." << std::endl;
453 if(!co[
"next_unit_id"].empty() && co[
"next_unit_id"] != cn[
"next_unit_id"]) {
454 msg <<
"Our next unit id is " << cn[
"next_unit_id"].to_int() <<
" but during the original the next unit id was "
455 << co[
"next_unit_id"].to_int() << std::endl;
458 if(!
msg.str().empty()) {
472 LOG_REPLAY <<
"set_scontext_synced:: destructor";
482 return new_rng_->get_random_calls();
virtual void error(const std::string &message)
Called when synced_context::run received nonsensial data based on the current gamestate.
void clear()
Clears the stack of undoable (and redoable) actions.
A class to check whether the results that were calculated in the replay match the results calculated ...
virtual bool local_checkup(const config &expected_data, config &real_data)=0
Compares data to the results calculated during the original game.
Variant for storing WML attributes.
std::string str(const std::string &fallback="") const
A config object defines a single node in a WML file, with access to child nodes.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
std::string debug() const
virtual void play_slice()
n_unit::id_manager & unit_id_manager()
bool end_turn_forced() const
const randomness::mt_rng & rng() const
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
randomness::rng * old_rng_
This checkup always compares the results in from different clients in a mp game but it also causes mo...
std::size_t get_save_id() const
Used for saving id to savegame.
void maybe_throw_return_to_play_side() const
int get_server_request_number() const
void check_victory()
Checks to see if a side has won.
void increase_server_request_number()
bool is_regular_game_end() const
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
virtual bool is_networked_mp() const
virtual void send_actions()
Sends replay [command]s to the server.
virtual void receive_actions()
Reads and executes replay [command]s from the server.
uint32_t get_next_random()
Get a new random number.
static rng & default_instance()
void add_synced_command(const std::string &name, const config &command)
void user_input(const std::string &name, const config &input, int from_side)
adds a user_input to the replay
static void process_error(const std::string &msg)
config * get_next_action()
std::shared_ptr< randomness::rng > new_rng_
~set_scontext_synced_base()
randomness::rng * old_rng_
set_scontext_synced_base()
A RAII object to enter the synced context, cannot be called if we are already in a synced context.
void do_final_checkup(bool dont_throw=false)
static checkup * generate_checkup(const std::string &tagname)
const std::unique_ptr< checkup > new_checkup_
This checkup compares whether the results calculated during the original game match the ones calculat...
static map & registry()
using static function variable instead of static member variable to prevent static initialization fia...
virtual config request() const =0
The request which is sent to the mp server.
void send_request() const
virtual const char * name() const =0
virtual config local_choice() const =0
We are in a game with no mp server and need to do this choice locally.
static void set_last_unit_id(int id)
static bool undo_blocked()
static std::shared_ptr< randomness::rng > get_rng_for_action()
static config ask_server_choice(const server_choice &)
If we are in a mp game, ask the server, otherwise generate the answer ourselves.
static bool run_in_synced_context_if_not_already(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
Checks whether we are currently running in a synced context, and if not we enters it.
static bool is_undo_blocked_
As soon as get_user_choice is used with side != current_side (for example in generate_random_seed) ot...
static bool run(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
Sets the context to 'synced', initialises random context, and calls the given function.
static void add_undo_commands(const config &commands, const game_events::queued_event &ctx)
static event_list undo_commands_
Actions to be executed when the current action is undone.
static void reset_undo_commands()
static std::string generate_random_seed()
Generates a new seed for a synced event, by asking the 'server'.
static int get_unit_id_diff()
static synced_state get_synced_state()
static void pull_remote_user_input()
called from get_user_choice while waiting for a remove user choice.
static void reset_block_undo()
static bool is_unsynced()
static void block_undo(bool do_block=true, bool clear_undo=true)
set this to false to prevent clearing the undo stack, this is important when we cannot change the gam...
static int last_unit_id_
Used to restore the unit id manager when undoing.
static void set_synced_state(synced_state newstate)
Should only be called form set_scontext_synced, set_scontext_local_choice.
static void send_user_choice()
called from get_user_choice to send a recently made choice to the other clients.
static bool run_and_store(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
static action_spectator & get_default_spectator()
An object to be passed to run_in_synced_context to assert false on error (the default).
static bool ignore_undo()
static bool run_and_throw(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
Definitions for the interface to Wesnoth Markup Language (WML).
Standard logging facilities (interface).
rng * generator
This generator is automatically synced during synced context.
actions::undo_list * undo_stack
game_classification * classification
play_controller * controller
std::shared_ptr< wb::manager > whiteboard
std::string next_seed_str()
std::string::const_iterator iterator
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
REPLAY_RETURN do_replay_handle(bool one_move)
checkup * checkup_instance
static lg::log_domain log_replay("replay")
Various functions that implement the undoing (and redoing) of in-game commands.