The Battle for Wesnoth  1.15.12+dev
synced_context.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "game_events/pump.hpp" // for queued_event
18 #include "generic_event.hpp"
19 #include "mouse_handler_base.hpp"
20 #include "random.hpp"
21 #include "random_synced.hpp"
22 #include "replay.hpp"
23 #include "synced_checkup.hpp"
24 #include "synced_commands.hpp"
25 
26 #include <deque>
27 #include <functional>
28 
29 class config;
30 
31 // only static methods.
33 {
34 public:
36 
37  /**
38  * Sets the context to 'synced', initialises random context, and calls the given function.
39  * The plan is that in replays and in real game the same function is called.
40  * However, if you cannot call this function you can also use set_scontext_synced directly
41  * (use it like it's used in this method).
42  *
43  * Movement commands are currently treated specially because actions::move_unit returns a
44  * value and some function use that value. Maybe I should add a way to return a value here.
45  *
46  * AI attacks are also treated special because the ai wants to pass advancement_aspects.
47  *
48  * Redoing does normally not take place in a synced context, because we saved the dependent=true
49  * replay commands in the replay stack data. There are also no events of similar fired when
50  * redoing an action (in most cases).
51  *
52  * @param commandname The command to run.
53  * @param data The data to use with the command.
54  * @param use_undo This parameter is used to ignore undos during an ai move to optimize.
55  * @param show
56  * @param error_handler An error handler for the case that data contains invalid data.
57  *
58  * @return True if the action was successful.
59  */
60  static bool run(const std::string& commandname,
61  const config& data,
62  bool use_undo = true,
63  bool show = true,
65 
66  static bool run_and_store(const std::string& commandname,
67  const config& data,
68  bool use_undo = true,
69  bool show = true,
71 
72  static bool run_and_throw(const std::string& commandname,
73  const config& data,
74  bool use_undo = true,
75  bool show = true,
77 
78  /**
79  * Checks whether we are currently running in a synced context, and if not we enters it.
80  * This is never called from so_replay_handle.
81  */
82  static bool run_in_synced_context_if_not_already(const std::string& commandname,
83  const config& data,
84  bool use_undo = true,
85  bool show = true,
87 
88  /**
89  * @return Whether we are currently executing a synced action like recruit, start, recall, disband, movement,
90  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar.
91  */
93  {
94  return state_;
95  }
96 
97  /**
98  * @return Whether we are currently executing a synced action like recruit, start, recall, disband, movement,
99  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar.
100  */
101  static bool is_synced()
102  {
103  return get_synced_state() == SYNCED;
104  }
105 
106  /**
107  * @return Whether we are not currently executing a synced action like recruit, start, recall, disband, movement,
108  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar. and not doing a local choice.
109  */
110  static bool is_unsynced()
111  {
112  return get_synced_state() == UNSYNCED;
113  }
114 
115  /** Should only be called form set_scontext_synced, set_scontext_local_choice */
116  static void set_synced_state(synced_state newstate)
117  {
118  state_ = newstate;
119  }
120 
121  /** Generates a new seed for a synced event, by asking the 'server' */
122  static std::string generate_random_seed();
123 
124  /** called from get_user_choice while waiting for a remove user choice. */
125  static void pull_remote_user_input();
126 
127  /**
128  * called from get_user_choice to send a recently made choice to the other clients.
129  * Does not receive any data from the network any sends data.
130  */
131  static void send_user_choice();
132 
133  /** A function to be passed to run_in_synced_context to assert false on error (the default). */
134  static void default_error_function(const std::string& message);
135 
136  /** A function to be passed to run_in_synced_context to log the error. */
137  static void just_log_error_function(const std::string& message);
138 
139  /** A function to be passed to run_in_synced_context to ignore the error. */
140  static void ignore_error_function(const std::string& message);
141 
142  /** @return A rng_deterministic if in determinsic mode otherwise a rng_synced. */
143  static std::shared_ptr<randomness::rng> get_rng_for_action();
144 
145  /** @return whether we already sent data about the current action to other clients. which means we cannot undo it. */
146  static bool is_simultaneous()
147  {
148  return is_simultaneous_;
149  }
150 
151  /** Sets is_simultaneous_ = false, called when entering the synced context. */
152  static void reset_is_simultaneous()
153  {
154  is_simultaneous_ = false;
155  }
156 
157  /** Sets is_simultaneous_ = true, called using a user choice that is not the currently playing side. */
158  static void set_is_simultaneous();
159 
160  /** @return Whether there were recently no methods called that prevent undoing. */
161  static bool can_undo();
162 
163  static void set_last_unit_id(int id)
164  {
165  last_unit_id_ = id;
166  }
167 
168  static int get_unit_id_diff();
169 
171  {
172  public:
173  virtual ~server_choice()
174  {
175  }
176 
177  /** We are in a game with no mp server and need to do this choice locally. */
178  virtual config local_choice() const = 0;
179 
180  /** The request which is sent to the mp server. */
181  virtual config request() const = 0;
182 
183  virtual const char* name() const = 0;
184  void send_request() const;
185  };
186 
187  /** If we are in a mp game, ask the server, otherwise generate the answer ourselves. */
188  static config ask_server_choice(const server_choice&);
189 
190  typedef std::deque<std::pair<config, game_events::queued_event>> event_list;
191  static event_list& get_undo_commands()
192  {
193  return undo_commands_;
194  }
195 
196  static void add_undo_commands(const config& commands, const game_events::queued_event& ctx);
197 
198  static void reset_undo_commands()
199  {
200  undo_commands_.clear();
201  }
202 
203 private:
204  /** Weather we are in a synced move, in a user_choice, or none of them. */
206 
207  /**
208  * As soon as get_user_choice is used with side != current_side (for example in generate_random_seed) other sides
209  * execute the command simultaneously and is_simultaneously is set to true. It's impossible to undo data that has
210  * been sent over the network.
211  *
212  * false = we are on a local turn and haven't sent anything yet.
213  *
214  * TODO: it would be better if the following variable were not static.
215  */
216  static inline bool is_simultaneous_ = false;
217 
218  /** Used to restore the unit id manager when undoing. */
219  static inline int last_unit_id_ = 0;
220 
221  /** Actions wml to be executed when the current action is undone. */
222  static inline event_list undo_commands_ {};
223 };
224 
226 {
227 public:
230 
231 protected:
232  std::shared_ptr<randomness::rng> new_rng_;
234 };
235 
236 /** A RAII object to enter the synced context, cannot be called if we are already in a synced context. */
238 {
239 public:
241 
242  /** Use this constructor if you have multiple synced_context but only one replay entry. */
243  set_scontext_synced(int num);
244 
246 
247  int get_random_calls();
248  void do_final_checkup(bool dont_throw = false);
249 
250 private:
251  // only called by constructors.
252  void init();
253  static checkup* generate_checkup(const std::string& tagname);
255  const std::unique_ptr<checkup> new_checkup_;
258 };
259 
260 /**
261  * A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
262  * Can only be used from inside a synced context.
263  */
265 {
266 public:
269 
270 private:
272 };
273 
274 /**
275  * An object to leave the synced context during draw or unsynced wml items when we don’t know whether we are in a
276  * synced context or not. if we are in a synced context we leave the synced context, otherwise it has no effect. we need
277  * This because we might call lua's wesnoth.interface.game_display during draw and we don’t want to have that an effect
278  * on the gamestate in this case.
279  */
281 {
282 public:
284 
285 private:
286  const std::unique_ptr<leave_synced_context> leaver_;
287 };
static void add_undo_commands(const config &commands, const game_events::queued_event &ctx)
static synced_state get_synced_state()
static bool run_and_store(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
static bool is_unsynced()
static bool is_simultaneous()
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 &#39;synced&#39;, initialises random context, and calls the given function.
static void set_synced_state(synced_state newstate)
Should only be called form set_scontext_synced, set_scontext_local_choice.
static std::string generate_random_seed()
Generates a new seed for a synced event, by asking the &#39;server&#39;.
static void set_is_simultaneous()
Sets is_simultaneous_ = true, called using a user choice that is not the currently playing side...
static event_list undo_commands_
Actions wml to be executed when the current action is undone.
static bool is_simultaneous_
As soon as get_user_choice is used with side != current_side (for example in generate_random_seed) ot...
virtual config local_choice() const =0
We are in a game with no mp server and need to do this choice locally.
A RAII object to enter the synced context, cannot be called if we are already in a synced context...
randomness::rng * old_rng_
Replay control code.
An object to leave the synced context during draw or unsynced wml items when we don’t know whether w...
static void just_log_error_function(const std::string &message)
A function to be passed to run_in_synced_context to log the error.
std::shared_ptr< randomness::rng > new_rng_
struct utils::detail::formula_initer init
virtual const char * name() const =0
static void reset_undo_commands()
events::command_disabler disabler_
static bool can_undo()
std::function< void(const std::string &)> error_handler_function
static void send_user_choice()
called from get_user_choice to send a recently made choice to the other clients.
static void pull_remote_user_input()
called from get_user_choice while waiting for a remove user choice.
static int last_unit_id_
Used to restore the unit id manager when undoing.
static bool is_synced()
static synced_state state_
Weather we are in a synced move, in a user_choice, or none of them.
const std::unique_ptr< leave_synced_context > leaver_
A class to check whether the results that were calculated in the replay match the results calculated ...
std::deque< std::pair< config, game_events::queued_event > > event_list
static int get_unit_id_diff()
randomness::rng * old_rng_
Define the game&#39;s event mechanism.
static void set_last_unit_id(int id)
static void ignore_error_function(const std::string &message)
A function to be passed to run_in_synced_context to ignore the error.
static void default_error_function(const std::string &message)
A function to be passed to run_in_synced_context to assert false on error (the default).
const std::unique_ptr< checkup > new_checkup_
static bool run_and_throw(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
static void reset_is_simultaneous()
Sets is_simultaneous_ = false, called when entering the synced context.
static bool run_in_synced_context_if_not_already(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
Checks whether we are currently running in a synced context, and if not we enters it...
static std::shared_ptr< randomness::rng > get_rng_for_action()
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
static event_list & get_undo_commands()
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
virtual config request() const =0
The request which is sent to the mp server.
static config ask_server_choice(const server_choice &)
If we are in a mp game, ask the server, otherwise generate the answer ourselves.
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:139
this class does not give synced random results derived classes might do.
Definition: random.hpp:27