The Battle for Wesnoth  1.19.5+dev
synced_context.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 #include "game_events/pump.hpp" // for queued_event
19 #include "mouse_handler_base.hpp"
20 #include "random.hpp"
21 #include "synced_checkup.hpp"
22 #include "synced_commands.hpp"
23 
24 #include <deque>
25 
26 
27 // only static methods.
29 {
30 public:
32 
33  /**
34  * Sets the context to 'synced', initialises random context, and calls the given function.
35  * The plan is that in replays and in real game the same function is called.
36  * However, if you cannot call this function you can also use set_scontext_synced directly
37  * (use it like it's used in this method).
38  *
39  * @param commandname The command to run.
40  * @param data The data to use with the command.
41  * @param spectator An error handler for the case that data contains invalid data.
42  *
43  * @return True if the action was successful.
44  */
45  static bool run(
46  const std::string& commandname, const config& data, action_spectator& spectator = get_default_spectator());
47 
48  static bool run_and_store(
49  const std::string& commandname, const config& data, action_spectator& spectator = get_default_spectator());
50 
51  static bool run_and_throw(
52  const std::string& commandname, const config& data, action_spectator& spectator = get_default_spectator());
53 
54  /**
55  * Checks whether we are currently running in a synced context, and if not we enters it.
56  * This is never called from so_replay_handle.
57  */
59  const std::string& commandname, const config& data, action_spectator& spectator = get_default_spectator());
60 
61  /**
62  * @return Whether we are currently executing a synced action like recruit, start, recall, disband, movement,
63  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar.
64  */
66  {
67  return state_;
68  }
69 
70  /**
71  * @return Whether we are currently executing a synced action like recruit, start, recall, disband, movement,
72  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar.
73  */
74  static bool is_synced()
75  {
76  return get_synced_state() == SYNCED;
77  }
78 
79  /**
80  * @return Whether we are not currently executing a synced action like recruit, start, recall, disband, movement,
81  * attack, init_side, end_turn, fire_event, lua_ai, auto_shroud or similar. and not doing a local choice.
82  */
83  static bool is_unsynced()
84  {
85  return get_synced_state() == UNSYNCED;
86  }
87 
88  /** Should only be called form set_scontext_synced, set_scontext_local_choice */
89  static void set_synced_state(synced_state newstate)
90  {
91  state_ = newstate;
92  }
93 
94  /** Generates a new seed for a synced event, by asking the 'server' */
95  static std::string generate_random_seed();
96 
97  /** called from get_user_choice while waiting for a remove user choice. */
98  static void pull_remote_user_input();
99 
100  /**
101  * called from get_user_choice to send a recently made choice to the other clients.
102  * Does not receive any data from the network any sends data.
103  */
104  static void send_user_choice();
105 
106  /** An object to be passed to run_in_synced_context to assert false on error (the default). */
108 
109  /** @return A rng_deterministic if in determinsic mode otherwise a rng_synced. */
110  static std::shared_ptr<randomness::rng> get_rng_for_action();
111 
112  /**
113  * @a set this to false to prevent clearing the undo stack, this is important when we cannot change the gamestate
114  * becasue with dsu clearing the undo stack changes the gamestate, which we for example don't want during formula
115  * evaluation, when it used the dice operator. TODO: consider removing this parameter when dsu is removed.
116  */
117  static void block_undo(bool do_block = true, bool clear_undo = true);
118  static void reset_block_undo()
119  {
120  is_undo_blocked_ = false;
121  }
122 
123  /** @return Whether we tracked something that can never be undone. */
124  static bool undo_blocked();
125 
126  static void set_last_unit_id(int id)
127  {
128  last_unit_id_ = id;
129  }
130 
131  static int get_unit_id_diff();
132 
134  {
135  public:
136  virtual ~server_choice()
137  {
138  }
139 
140  /** We are in a game with no mp server and need to do this choice locally. */
141  virtual config local_choice() const = 0;
142 
143  /** The request which is sent to the mp server. */
144  virtual config request() const = 0;
145 
146  virtual const char* name() const = 0;
147 
148  int request_id() const;
149  void send_request() const;
150  };
151 
152  /** If we are in a mp game, ask the server, otherwise generate the answer ourselves. */
153  static config ask_server_choice(const server_choice&);
154 
155  struct event_info {
157  utils::optional<int> lua_;
159  event_info(const config& cmds, game_events::queued_event evt) : cmds_(cmds), evt_(evt) {}
160  event_info(int lua, game_events::queued_event evt) : lua_(lua), evt_(evt) {}
161  event_info(int lua, const config& args, game_events::queued_event evt) : cmds_(args), lua_(lua), evt_(evt) {}
162  };
163 
164  typedef std::deque<event_info> event_list;
166  {
167  return undo_commands_;
168  }
169 
170  static void add_undo_commands(const config& commands, const game_events::queued_event& ctx);
171  static void add_undo_commands(int fcn_idx, const game_events::queued_event& ctx);
172  static void add_undo_commands(int fcn_idx, const config& args, const game_events::queued_event& ctx);
173 
174  static void reset_undo_commands()
175  {
176  undo_commands_.clear();
177  }
178 
179  static bool ignore_undo();
180 private:
181  /** Weather we are in a synced move, in a user_choice, or none of them. */
183 
184  /**
185  * As soon as get_user_choice is used with side != current_side (for example in generate_random_seed) other sides
186  * execute the command simultaneously and is_simultaneously is set to true. It's impossible to undo data that has
187  * been sent over the network.
188  *
189  * false = we are on a local turn and haven't sent anything yet.
190  */
191  static inline bool is_undo_blocked_ = false;
192 
193  /** Used to restore the unit id manager when undoing. */
194  static inline int last_unit_id_ = 0;
195 
196  /** Actions to be executed when the current action is undone. */
197  static inline event_list undo_commands_ {};
198 };
199 
201 {
202 public:
205 
206 protected:
207  std::shared_ptr<randomness::rng> new_rng_;
209 };
210 
211 /** A RAII object to enter the synced context, cannot be called if we are already in a synced context. */
213 {
214 public:
216 
217  /** Use this constructor if you have multiple synced_context but only one replay entry. */
218  set_scontext_synced(int num);
219 
221 
222  int get_random_calls();
223  void do_final_checkup(bool dont_throw = false);
224 
225 private:
226  // only called by constructors.
227  void init();
228  static checkup* generate_checkup(const std::string& tagname);
230  const std::unique_ptr<checkup> new_checkup_;
233 };
234 
235 /**
236  * A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
237  * Can only be used from inside a synced context.
238  */
240 {
241 public:
244 
245 private:
247 };
248 
249 /**
250  * An object to leave the synced context during draw or unsynced wml items when we don’t know whether we are in a
251  * synced context or not. if we are in a synced context we leave the synced context, otherwise it has no effect. we need
252  * This because we might call lua's wesnoth.interface.game_display during draw and we don’t want to have that an effect
253  * on the gamestate in this case.
254  */
256 {
257 public:
259 
260 private:
261  const std::unique_ptr<leave_synced_context> leaver_;
262 };
A class to check whether the results that were calculated in the replay match the results calculated ...
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
A RAII object to temporary leave the synced context like in wesnoth.synchronize_choice.
randomness::rng * old_rng_
this class does not give synced random results derived classes might do.
Definition: random.hpp:28
std::shared_ptr< randomness::rng > new_rng_
randomness::rng * old_rng_
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)
events::command_disabler disabler_
const std::unique_ptr< checkup > new_checkup_
An object to leave the synced context during draw or unsynced wml items when we don’t know whether we...
const std::unique_ptr< leave_synced_context > leaver_
virtual config request() const =0
The request which is sent to the mp server.
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 synced_state state_
Weather we are in a synced move, in a user_choice, or none of them.
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.
std::deque< event_info > event_list
static bool is_synced()
static event_list & get_undo_commands()
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())
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:198
std::string_view data
Definition: picture.cpp:178
Define the game's event mechanism.
event_info(int lua, game_events::queued_event evt)
event_info(int lua, const config &args, game_events::queued_event evt)
game_events::queued_event evt_
utils::optional< int > lua_
event_info(const config &cmds, game_events::queued_event evt)