48 #define DBG_REPLAY LOG_STREAM(debug, log_replay) 49 #define LOG_REPLAY LOG_STREAM(info, log_replay) 50 #define WRN_REPLAY LOG_STREAM(warn, log_replay) 51 #define ERR_REPLAY LOG_STREAM(err, log_replay) 54 #define DBG_RND LOG_STREAM(debug, log_random) 55 #define LOG_RND LOG_STREAM(info, log_random) 56 #define WRN_RND LOG_STREAM(warn, log_random) 57 #define ERR_RND LOG_STREAM(err, log_random) 63 std::stringstream errbuf;
66 const std::size_t nunits = cfg[
"num_units"].to_size_t();
67 if(nunits != units.
size()) {
68 errbuf <<
"SYNC VERIFICATION FAILED: number of units from data source differ: " 69 << nunits <<
" according to data source. " << units.
size() <<
" locally\n";
71 std::set<map_location> locs;
77 if(units.
count(loc) == 0) {
78 errbuf <<
"data source says there is a unit at " 79 << loc <<
" but none found locally\n";
84 if (locs.count(j->get_location()) == 0) {
85 errbuf <<
"local unit at " << j->get_location()
86 <<
" but none in data source\n";
97 if(u == units.
end()) {
98 errbuf <<
"SYNC VERIFICATION FAILED: data source says there is a '" 99 << un[
"type"] <<
"' (side " << un[
"side"] <<
") at " 100 << loc <<
" but there is no local record of it\n";
110 using namespace std::literals::string_literals;
111 static const std::array fields{
"type"s,
"hitpoints"s,
"experience"s,
"side"s};
113 for(
const std::string& field : fields) {
114 if (u_cfg[field] != un[field]) {
115 errbuf <<
"ERROR IN FIELD '" << field <<
"' for unit at " 116 << loc <<
" data source: '" << un[field]
117 <<
"' local: '" << u_cfg[field] <<
"'\n";
123 errbuf <<
"(SYNC VERIFICATION FAILED)\n";
135 if (!speak[
"time"].empty())
137 std::stringstream ss(speak[
"time"].str());
143 time = std::time(
nullptr);
151 , text_(cfg[
"message"].str())
153 if(cfg[
"team_name"].empty() && cfg[
"to_sides"].empty())
155 nick_ = cfg[
"id"].str();
157 nick_ =
"*"+cfg[
"id"].str()+
"*";
159 int side = cfg[
"side"].to_int(0);
185 , message_locations()
244 val[
"value"] = value;
246 cmd.
add_child(
"countdown_update", std::move(val));
261 cmd[
"dependent"] =
true;
264 cmd[
"from_side"] =
"server";
268 cmd[
"from_side"] = from_side;
289 val[
"team_name"] = team_name;
290 val[
"force"] = force;
291 cmd.
add_child(
"clear_labels", std::move(val));
310 end_turn[
"next_player_number"] = next_player_number;
370 std::vector<int>::reverse_iterator loc_it;
384 std::vector<int>::const_iterator loc_it;
385 int last_location = 0;
386 std::back_insert_iterator<std::vector < chat_msg >> chat_log_appender( back_inserter(message_log));
389 last_location = *loc_it;
403 for (
int cmd = cmd_start; cmd < cmd_end; ++cmd)
408 if ((data_type ==
ALL_DATA || !cc[
"undo"].to_bool(
true)) && !cc[
"sent"].to_bool(
false))
441 for (
int cmd_num =
base_->
get_pos() - 1; cmd_num >= 0; --cmd_num)
445 if (cc[
"dependent"].to_bool(
false) || !cc[
"undo"].to_bool(
true) || cc[
"async"].to_bool(
false))
451 ERR_REPLAY <<
"replay::get_last_real_command called with no existent command.";
452 assert(
false &&
"replay::get_last_real_command called with no existent command.");
453 throw "replay::get_last_real_command called with no existent command.";
465 std::vector<map_location> steps;
470 WRN_REPLAY <<
"Warning: Path data contained something which could not be parsed to a sequence of locations:" <<
"\n config = " << child->debug();
474 ERR_REPLAY <<
"trying to undo a move using an empty path";
480 if (dst == aloc) src.
write(async_child);
511 for (; cmd_index >= 0; --cmd_index)
518 if(c[
"undo"].to_bool(
true) && !c[
"async"].to_bool(
false) && !c[
"dependent"].to_bool(
false))
520 if(c[
"sent"].to_bool(
false))
522 ERR_REPLAY <<
"trying to undo a command that was already sent.";
534 ERR_REPLAY <<
"trying to undo a command but no command was found.";
542 if(!cc[
"undo"].to_bool(
true))
546 else if(cc[
"async"].to_bool(
false))
557 else if(cc[
"dependent"].to_bool(
false) ||
i == cmd_index)
565 ERR_REPLAY <<
"Couldn't handle command:\n" << cc <<
"\nwhen undoing.";
601 const bool was_at_end =
at_end();
607 assert(was_at_end ==
at_end());
659 cmd_cfg[
"sent"] =
true;
662 cmd_cfg[
"undo"] =
false;
716 DBG_REPLAY <<
"in do replay with is_synced=" << is_synced <<
"is_unsynced=" << is_unsynced;
731 if (ch_itors.empty() || cfg->
has_child(
"start"))
740 const std::string &team_name =
speak[
"to_sides"];
741 const std::string &speaker_name =
speak[
"id"];
742 const std::string &message =
speak[
"message"];
744 bool is_whisper = (speaker_name.find(
"whisper: ") == 0);
746 DBG_REPLAY <<
"tried to add a chat message twice.";
748 int side =
speak[
"side"];
756 else if (cfg->
child(
"surrender"))
760 else if (
const config &label_config = cfg->
child(
"label"))
774 else if (
const config &rename = cfg->
child(
"rename"))
777 const std::string &name = rename[
"name"];
780 if (u.
valid() && !u->unrenamable()) {
789 WRN_REPLAY <<
"attempt to rename unit at location: " 790 << loc << (u.
valid() ?
", which is unrenamable" :
", where none exists (anymore)");
794 else if (cfg->
child(
"init_side"))
823 if (
const config &cfg_verify = cfg->
child(
"verify")) {
830 else if (
const config &countdown_update = cfg->
child(
"countdown_update"))
832 int val = countdown_update[
"value"];
833 int tval = countdown_update[
"team"];
835 std::stringstream errbuf;
836 errbuf <<
"Illegal countdown update \n" 837 <<
"Received update for :" << tval <<
" Current user :" 838 << side_num <<
"\n" <<
" Updated value :" << val;
845 else if ((*cfg)[
"dependent"].to_bool(
false))
859 DBG_REPLAY <<
"got an dependent action name = " << child_name;
877 LOG_REPLAY <<
"found commandname " << commandname <<
"in replay";
882 else if((*cfg)[
"side_invalid"].to_bool(
false)) {
883 ERR_REPLAY <<
"received a synced [command] from side " << (*cfg)[
"from_side"].to_int(0) <<
". Sent from wrong client.";
922 if(data.
empty() ==
false) {
936 if(data.
empty() ==
false) {
void end_turn(int next_player_number)
play_controller * controller
void delete_upcoming_commands()
const map_location & location() const
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
static synced_state get_synced_state()
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
replay(replay_recorder_base &base)
const color_t & color() const
void set_countdown_time(const int amount) const
static display * get_singleton()
Returns the display object if a display object exists.
const_all_children_itors all_children_range() const
In-order iteration over all children.
replay_network_sender(replay &obj)
void add_countdown_update(int value, int team)
virtual const unit_map & units() const override
config & get_upload_log()
void speak(const config &cfg)
bool add_chat_message_location()
adds a chat message if it wasn't added yet.
void write(config &res) const
boost::iterator_range< const_all_children_iterator > const_all_children_itors
void add_log_data(const std::string &key, const std::string &var)
static bool run(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
Sets the context to 'synced', initialises random context, and calls the given function.
const std::vector< chat_msg > & build_chat_log() const
New lexcical_cast header.
config & command(int) const
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
const t_string & text() const
child_itors child_range(config_key_type key)
config & insert_command(int index)
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
const std::string & team_name() const
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
config & child_or_add(config_key_type key)
Returns a reference to the first child with the given key.
REPLAY_RETURN do_replay(bool one_move)
static void show_oos_error_error_function(const std::string &message)
config & get_last_real_command()
replay_recorder_base * base_
void add_synced_command(const std::string &name, const config &command)
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
static std::string get_side_highlight_pango(int side)
static void verify(const unit_map &units, const config &cfg)
This class stores all the data for a single 'side' (in game nomenclature).
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
void redo(const config &dst, bool set_to_end=false)
bool add_start_if_not_there_yet()
std::string label
What to show in the filter's drop-down list.
static std::time_t get_time(const config &speak)
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
void remove_command(int index)
void clear(const std::string &, bool force)
void recalculate_minimap()
Schedule the minimap for recalculation.
void add_surrender(int side_number)
config & add_child_at(config_key_type key, const config &val, unsigned index)
void user_input(const std::string &name, const config &input, int from_side)
adds a user_input to the replay
unsigned all_children_count() const
void add_rename(const std::string &name, const map_location &loc)
std::string get_checksum(const unit &u, backwards_compatibility::unit_checksum_version version)
Gets a checksum for a unit.
utils::optional_reference< config > optional_child(config_key_type key, int n=0)
Euivalent to child, but returns an empty optional if the nth child was not found. ...
std::size_t count(const map_location &loc) const
bool is_ignored(const std::string &nick)
static std::vector< chat_msg > message_log
void add_unit_checksum(const map_location &loc, config &cfg)
config & get_command_at(int pos)
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
Encapsulates the map of the game.
unit_iterator find(std::size_t id)
std::shared_ptr< wb::manager > whiteboard
static void process_error(const std::string &msg)
static map_location::DIRECTION s
#define log_scope(description)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
config & add_child(config_key_type key)
const_all_children_iterator ordered_begin() const
display_chat_manager & get_chat_manager()
To store label data Class implements logic for rendering.
config & add_nonundoable_command()
adds a new command to the command list at the current position.
static lg::log_domain log_replay("replay")
void add_config(const config &cfg, MARK_SENT mark=MARK_AS_UNSENT)
std::vector< int > message_locations
Various functions that implement the undoing (and redoing) of in-game commands.
void undo_cut(config &dst)
Standard logging facilities (interface).
int current_side() const
Returns the number of the side whose turn it is.
Container associating units to locations.
config * get_next_action()
void delete_upcoming_commands()
bool parse_should_show_lobby_join(const std::string &sender, const std::string &message)
config & add_command()
Adds a new empty command to the command list at the end.
static lg::log_domain log_random("random")
A config object defines a single node in a WML file, with access to child nodes.
static bool fix_rename_command(const config &c, config &async_child)
fixes a rename command when undoing a earlier command.
REPLAY_RETURN do_replay_handle(bool one_move)
static map_location::DIRECTION n
Thrown when a lexical_cast fails.
void clear_labels(const std::string &, bool)
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
std::string debug() const
chat_msg(const config &cfg)
void add_chat_log_entry(const config &speak, std::back_insert_iterator< std::vector< chat_msg >> &i) const
static game_display * get_singleton()
void add_label(const terrain_label *)
config get_data_range(int cmd_start, int cmd_end, DATA_TYPE data_type=ALL_DATA) const
void write(config &cfg) const