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 , sent_upto_(base.
size())
186 , message_locations()
245 val[
"value"] = value;
247 cmd.
add_child(
"countdown_update", std::move(val));
262 cmd[
"dependent"] =
true;
265 cmd[
"from_side"] =
"server";
269 cmd[
"from_side"] = from_side;
290 val[
"team_name"] = team_name;
291 val[
"force"] = force;
292 cmd.
add_child(
"clear_labels", std::move(val));
311 end_turn[
"next_player_number"] = next_player_number;
362 if (!
prefs::get().parse_should_show_lobby_join(cfg[
"id"], cfg[
"message"]))
return;
363 if (
prefs::get().is_ignored(cfg[
"id"]))
return;
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;
406 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.";
461 if (
const auto child =
c.optional_child(
"move"))
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);
485 auto loc =
c.optional_child(
"recruit");
487 loc =
c.optional_child(
"recall");
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))
548 if(
auto rename =
c.optional_child(
"rename"))
557 else if(cc[
"dependent"].to_bool(
false) ||
i == cmd_index)
560 dst.add_child_at(
"command",
config(), 0).swap(
c);
565 ERR_REPLAY <<
"Couldn't handle command:\n" << cc <<
"\nwhen undoing.";
600 const bool was_at_end =
at_end();
606 assert(was_at_end ==
at_end());
669 cmd_cfg[
"sent"] =
true;
672 cmd_cfg[
"undo"] =
false;
698 if(key ==
"speak" || key ==
"label" || key ==
"surrender" || key ==
"clear_labels" || key ==
"rename" || key ==
"countdown_update") {
701 if(command[
"dependent"].to_bool(
false)) {
736 DBG_REPLAY <<
"in do replay with is_synced=" << is_synced <<
"is_unsynced=" << is_unsynced;
751 if (ch_itors.empty() || cfg->
has_child(
"start"))
760 const std::string &team_name = speak[
"to_sides"];
761 const std::string &speaker_name = speak[
"id"];
762 const std::string &message = speak[
"message"];
764 bool is_whisper = (speaker_name.find(
"whisper: ") == 0);
766 DBG_REPLAY <<
"tried to add a chat message twice.";
768 int side = speak[
"side"].to_int();
797 const std::string &name = rename[
"name"];
800 if (u.
valid() && !u->unrenamable()) {
809 WRN_REPLAY <<
"attempt to rename unit at location: "
810 << loc << (u.
valid() ?
", which is unrenamable" :
", where none exists (anymore)");
846 if(
int npn = end_turn[
"next_player_number"].to_int(0); npn > 0) {
853 else if (
auto countdown_update = cfg->
optional_child(
"countdown_update"))
855 auto val = chrono::parse_duration<std::chrono::milliseconds>(countdown_update[
"value"]);
856 int tval = countdown_update[
"team"].to_int();
858 std::stringstream errbuf;
859 errbuf <<
"Illegal countdown update \n"
860 <<
"Received update for :" << tval <<
" Current user :"
861 << side_num <<
"\n" <<
" Updated value :" << val.count();
868 else if ((*cfg)[
"dependent"].to_bool(
false))
882 DBG_REPLAY <<
"got an dependent action name = " << child_name;
899 LOG_REPLAY <<
"found commandname " << commandname <<
"in replay";
904 else if((*cfg)[
"side_invalid"].to_bool(
false)) {
905 ERR_REPLAY <<
"received a synced [command] from side " << (*cfg)[
"from_side"].to_int(0) <<
". Sent from wrong client.";
chat_msg(const config &cfg)
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.
auto all_children_view() const
In-order iteration over all children.
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
child_itors child_range(config_key_type key)
config & child_or_add(config_key_type key)
Returns a reference to the first child with the given key.
std::size_t all_children_count() const
std::string debug() const
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
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)
void recalculate_minimap()
Schedule the minimap for recalculation.
static display * get_singleton()
Returns the display object if a display object exists.
virtual const unit_map & units() const override
void set_phase(PHASE phase)
@ TURN_ENDED
The turn_end, side_turn_end etc [events] are fired next phase: TURN_STARTING_WAITING (default),...
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
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 clear(const std::string &, bool force)
virtual void process_oos(const std::string &msg) const
Asks the user whether to continue on an OOS error.
void do_init_side()
Called by replay handler or init_side() to do actual work for turn change.
int current_side() const
Returns the number of the side whose turn it is.
void delete_upcoming_commands()
config & get_upload_log()
config & get_command_at(int pos)
config & insert_command(int index)
void remove_command(int index)
config * peek_next_action()
void add_rename(const std::string &name, const map_location &loc)
config & add_nonundoable_command()
adds a new command to the command list at the current position.
bool add_start_if_not_there_yet()
void undo_cut(config &dst)
config & get_last_real_command()
void add_config(const config &cfg, MARK_SENT mark=MARK_AS_UNSENT)
void add_label(const terrain_label *)
void add_synced_command(const std::string &name, const config &command)
void end_turn(int next_player_number)
void add_surrender(int side_number)
void speak(const config &cfg)
void clear_labels(const std::string &, bool)
const std::vector< chat_msg > & build_chat_log() const
config & command(int) const
replay(replay_recorder_base &base)
void user_input(const std::string &name, const config &input, int from_side)
adds a user_input to the replay
void redo(const config &dst, bool set_to_end=false)
void add_unit_checksum(const map_location &loc, config &cfg)
std::vector< int > message_locations
static void process_error(const std::string &msg)
void delete_upcoming_commands()
config get_unsent_commands(DATA_TYPE data_type)
void add_countdown_update(int value, int team)
replay_recorder_base * base_
bool add_chat_message_location()
adds a chat message if it wasn't added yet.
void add_chat_log_entry(const config &speak, std::back_insert_iterator< std::vector< chat_msg >> &i) const
void add_log_data(const std::string &key, const std::string &var)
config & add_command()
Adds a new empty command to the command list at the end.
config * get_next_action()
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 synced_state get_synced_state()
This class stores all the data for a single 'side' (in game nomenclature).
static std::string get_side_highlight_pango(int side)
void set_countdown_time(const std::chrono::milliseconds &amount) const
To store label data Class implements logic for rendering.
Container associating units to locations.
std::size_t count(const map_location &loc) const
unit_iterator find(std::size_t id)
static std::string _(const char *str)
std::string label
What to show in the filter's drop-down list.
New lexcical_cast header.
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
Standard logging facilities (interface).
#define log_scope(description)
play_controller * controller
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.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
REPLAY_ACTION_TYPE get_replay_action_type(const config &command)
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 lg::log_domain log_replay("replay")
REPLAY_RETURN do_replay(bool one_move)
static lg::log_domain log_random("random")
static void verify(const unit_map &units, const config &cfg)
static std::time_t get_time(const config &speak)
static std::vector< chat_msg > message_log
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Thrown when a lexical_cast fails.
Encapsulates the map of the game.
void write(config &cfg) const
bool empty() const
False if both w and h are > 0, true otherwise.
static map_location::direction n
static map_location::direction s
std::string get_checksum(const unit &u, backwards_compatibility::unit_checksum_version version)
Gets a checksum for a unit.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE(cond, message)
The macro to use for the validation of WML.