34 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
35 #define LOG_REPLAY LOG_STREAM(info, log_replay)
36 #define WRN_REPLAY LOG_STREAM(warn, log_replay)
37 #define ERR_REPLAY LOG_STREAM(err, log_replay)
41 using namespace std::chrono_literals;
42 class user_choice_notifer_ingame
47 std::chrono::steady_clock::time_point start_show_;
50 user_choice_notifer_ingame()
53 , start_show_(std::chrono::steady_clock::now() + 2000ms)
58 ~user_choice_notifer_ingame()
65 void update(
const std::string& message)
67 if(label_id_ == -1 && std::chrono::steady_clock::now() > start_show_)
71 if(message == message_) {
81 void start_show_label()
83 assert(label_id_ == -1);
96 assert(label_id_ != -1);
114 replay::process_error(
"MP synchronization only works in a synced context (for example Select or preload events are no synced context).\n");
115 return std::map<int,config>();
118 for(
int side : sides)
120 if(1 > side || side > max_side)
123 return std::map<int,config>();
130 std::set<int> empty_sides;
131 for(
int side : sides)
135 empty_sides.insert(side);
139 for(
int side : empty_sides)
146 for(
int side : empty_sides)
164 bool is_side_null_controlled;
167 if(side < 1 || max_side < side) {
169 ERR_REPLAY <<
"Invalid parameter for side in get_user_choice.";
181 LOG_REPLAY <<
"MP synchronization called during an unsynced context.";
204 <<
" is_synced=" << is_synced
205 <<
" is_mp_game=" << is_mp_game
206 <<
" is_side_null_controlled=" << is_side_null_controlled;
208 if (is_side_null_controlled)
210 DBG_REPLAY <<
"MP synchronization: side 1 being null-controlled in get_user_choice.";
216 while ( side <= max_side && resources::gameboard->get_team(side).is_empty() )
218 assert(side <= max_side);
222 assert(1 <= side && side <= max_side);
227 if(retv.find(side) == retv.end())
244 , changed_event_(
"user_choice_update")
251 assert(1 <= side && side <= max_side);
253 assert(!
t.is_empty());
288 int from_side = (*action)[
"from_side"].to_int(0);
289 if((*action)[
"side_invalid"].to_bool(
false) ==
true)
292 replay::process_error(
"MP synchronization: side_invalid in replay data, this could mean someone wants to cheat.\n");
296 replay::process_error(
"MP synchronization: we got an answer from side " + std::to_string(from_side) +
"for [" +
tagname_ +
"] which is not was we expected\n");
298 if(
res_.find(from_side) !=
res_.end())
300 replay::process_error(
"MP synchronization: we got already our answer from side " + std::to_string(from_side) +
"for [" +
tagname_ +
"] now we have it twice.\n");
322 std::vector<t_string> sides_str;
328 sides_str.push_back(std::to_string(side));
343 "waiting for $desc from side $sides",
344 "waiting for $desc from sides $sides",
346 {std::pair(
"desc", uch_.description()), std::pair(
"sides", utils::format_conjunct_list(
"", sides_str))}
360 DBG_REPLAY <<
"MP synchronization: local choice";
365 WRN_REPLAY <<
"Discarding a local choice because we found it already on the replay";
384 ERR_REPLAY <<
"A sync error appeared while waiting for a synced user choice of type '" <<
uch_.
description() <<
"' ([" +
tagname_ +
"]), doing the choice locally";
389 ERR_REPLAY <<
"Doing a local choice for side " << side;
398 user_choice_notifer_ingame notifer;
417 gui2::dialogs::synched_choice_wait::display(man);
452 static bool ucm_in_proccess =
false;
453 struct ucm_process_scope {
454 ucm_process_scope() { ucm_in_proccess =
true; }
455 ~ucm_process_scope() { ucm_in_proccess =
false; }
462 ucm_process_scope scope1;
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(bool is_delay_enabled=true)
rect map_outside_area() const
Returns the available area for a map, this may differ from the above.
static display * get_singleton()
Returns the display object if a display object exists.
virtual void notify_observers()
void set_position(double xpos, double ypos)
void set_lifetime(const std::chrono::milliseconds &lifetime, const std::chrono::milliseconds &fadeout=std::chrono::milliseconds{100})
void set_color(const color_t &color)
void set_clip_rect(const SDL_Rect &r)
void set_font_size(int font_size)
virtual const std::vector< team > & teams() const override
bool is_before_screen() const
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
int current_side() const
Returns the number of the side whose turn it is.
virtual bool is_networked_mp() const
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()
static bool undo_blocked()
static void pull_remote_user_input()
called from get_user_choice while waiting for a remove user choice.
static void send_user_choice()
called from get_user_choice to send a recently made choice to the other clients.
static void set_is_simultaneous()
Sets is_simultaneous_ = true, called using a user choice that is not the currently playing side.
This class stores all the data for a single 'side' (in game nomenclature).
events::generic_event changed_event_
bool waiting() const
Note: currently finished() does not imply !waiting() so you may need to check both.
std::string wait_message_
user_choice_manager(const std::string &name, const mp_sync::user_choice &uch, const std::set< int > &sides)
void update_local_choice()
std::set< int > required_
const mp_sync::user_choice & uch_
void process()
Inherited from events::pump_monitor.
static std::map< int, config > get_user_choice_internal(const std::string &name, const mp_sync::user_choice &uch, const std::set< int > &sides)
std::map< int, config > res_
const std::string & wait_message() const
const std::string & tagname_
bool has_local_choice() const
map_display and display: classes which take care of displaying the map and game-data on the screen.
Standard logging facilities (interface).
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
void remove_floating_label(int handle, const std::chrono::milliseconds &fadeout)
removes the floating label given by 'handle' from the screen
const color_t NORMAL_COLOR
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
std::map< int, config > get_user_choice_multiple_sides(const std::string &name, const user_choice &uch, std::set< int > sides)
Performs a choice for multiple sides for WML events.
play_controller * controller
REPLAY_RETURN do_replay_handle(bool one_move)
Interface for querying local choices.
virtual config query_user(int side) const =0
virtual std::string description() const
virtual bool is_visible() const
whether the choice is visible for the user like an advancement choice a non-visible choice is for exa...
virtual config random_choice(int side) const =0
static void wait_ingame(user_choice_manager &man)
static void wait_prestart(user_choice_manager &man)
static lg::log_domain log_replay("replay")