The Battle for Wesnoth  1.17.0-dev
manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
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 #include "game_events/manager.hpp"
17 
18 #include "game_events/handlers.hpp"
21 #include "game_events/pump.hpp"
22 
23 #include "formula/string_utils.hpp"
24 #include "game_data.hpp"
25 #include "log.hpp"
26 #include "resources.hpp"
28 
29 #include <iostream>
30 
31 static lg::log_domain log_engine("engine");
32 #define DBG_NG LOG_STREAM(debug, log_engine)
33 #define LOG_NG LOG_STREAM(info, log_engine)
34 #define WRN_NG LOG_STREAM(warn, log_engine)
35 
36 static lg::log_domain log_event_handler("event_handler");
37 #define DBG_EH LOG_STREAM(debug, log_event_handler)
38 
39 namespace
40 {
41  // Event handlers can't be destroyed as long as at least one of these locks exist.
42  class event_handler_list_lock
43  {
44  public:
45  event_handler_list_lock()
46  {
47  ++num_locks_;
48  }
49 
50  ~event_handler_list_lock()
51  {
52  --num_locks_;
53  }
54 
55  static bool none()
56  {
57  return num_locks_ == 0u;
58  }
59  private:
60  static unsigned int num_locks_;
61  };
62 
63  unsigned int event_handler_list_lock::num_locks_ = 0u;
64 }
65 
66 namespace game_events
67 {
68 /** Create an event handler. */
69 void manager::add_event_handler(const config& handler, bool is_menu_item)
70 {
71  event_handlers_->add_event_handler(handler, is_menu_item);
72 }
73 
74 /** Removes an event handler. */
75 void manager::remove_event_handler(const std::string& id)
76 {
77  event_handlers_->remove_event_handler(id);
78 }
79 
80 /** Gets an event handler by id */
81 const handler_ptr manager::get_event_handler_by_id(const std::string& id)
82 {
83  return event_handlers_->get_event_handler_by_id(id);
84 }
85 
86 /* ** manager ** */
87 
88 manager::manager()
89  : event_handlers_(new event_handlers())
90  , unit_wml_ids_()
91  , pump_(new game_events::wml_event_pump(*this))
92  , wml_menu_items_()
93 {
94 }
95 
96 void manager::read_scenario(const config& scenario_cfg)
97 {
98  for(const config& ev : scenario_cfg.child_range("event")) {
100  }
101 
102  for(const std::string& id : utils::split(scenario_cfg["unit_wml_ids"])) {
103  unit_wml_ids_.insert(id);
104  }
105 
106  wml_menu_items_.set_menu_items(scenario_cfg);
107 
108  // Create the event handlers for menu items.
110 }
111 
113 {
114 }
115 
116 void manager::add_events(const config::const_child_itors& cfgs, const std::string& type)
117 {
118  if(!type.empty()) {
119  if(std::find(unit_wml_ids_.begin(), unit_wml_ids_.end(), type) != unit_wml_ids_.end()) {
120  return;
121  }
122 
123  unit_wml_ids_.insert(type);
124  }
125 
126  for(const config& new_ev : cfgs) {
127  if(type.empty() && new_ev["id"].empty()) {
128  WRN_NG << "attempt to add an [event] with empty id=, ignoring " << std::endl;
129  continue;
130  }
131 
132  add_event_handler(new_ev);
133  }
134 }
135 
137 {
138  for(const handler_ptr& eh : event_handlers_->get_active()) {
139  if(!eh || eh->is_menu_item()) {
140  continue;
141  }
142 
143  // Silently skip disabled events if this function is invoked mid-event, such as via
144  // [inspect] (the inspector writes the events to a local config) or if an out-of-sync
145  // error occurs in MP. If the event in question is first-time-only, it will already
146  // have been flagged as disabled by this point (such events are disabled before their
147  // actions are run). If a disabled event is encountered outside an event context,
148  // however, assert. That means something went wrong with event list cleanup.
149  if(eh->disabled() && is_event_running()) {
150  continue;
151  } else {
152  assert(!eh->disabled());
153  }
154 
155  cfg.add_child("event", eh->get_config());;
156  }
157 
158  cfg["unit_wml_ids"] = utils::join(unit_wml_ids_);
160 }
161 
162 void manager::execute_on_events(const std::string& event_id, manager::event_func_t func)
163 {
164  const std::string standardized_event_id = event_handlers::standardize_name(event_id);
165  const game_data* gd = resources::gamedata;
166  auto& active_handlers = event_handlers_->get_active();
167 
168  // Save the end outside the loop so the end point remains constant,
169  // even if new events are added to the queue.
170  const unsigned saved_end = active_handlers.size();
171 
172 
173  {
174  // Ensure that event handlers won't be cleaned up while we're iterating them.
175  event_handler_list_lock lock;
176 
177  for (unsigned i = 0; i < saved_end; ++i) {
178  handler_ptr handler = nullptr;
179 
180  try {
181  handler = active_handlers.at(i);
182  }
183  catch (const std::out_of_range&) {
184  continue;
185  }
186 
187  // Shouldn't happen, but we're just being safe.
188  if (!handler || handler->disabled()) {
189  continue;
190  }
191 
192  // Could be more than one.
193  for (const std::string& name : handler->names()) {
194  bool matches = false;
195 
196  if (utils::might_contain_variables(name)) {
197  // If we don't have gamedata, we can't interpolate variables, so there's
198  // no way the name will match. Move on to the next one in that case.
199  if (!gd) {
200  continue;
201  }
202 
203  matches = standardized_event_id ==
205  }
206  else {
207  matches = standardized_event_id == name;
208  }
209 
210  if (matches) {
211  func(*this, handler);
212  break;
213  }
214  }
215  }
216  }
217 
218  // Clean up expired ptrs. This saves us effort later since it ensures every ptr is valid.
219  if(event_handler_list_lock::none()) {
220  event_handlers_->clean_up_expired_handlers(standardized_event_id);
221  }
222 }
223 
225 {
226  // If there is an event handler list lock, an event is being processed.
227  return !event_handler_list_lock::none();
228 }
229 
231 {
232  return *pump_;
233 }
234 
235 } // end namespace game_events
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
bool is_event_running() const
Definition: manager.cpp:224
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
static std::string standardize_name(const std::string &name)
Utility to standardize the event names used in by_name_.
child_itors child_range(config_key_type key)
Definition: config.cpp:361
game_data * gamedata
Definition: resources.cpp:23
void init_handlers() const
Initializes the implicit event handlers for inlined [command]s.
void read_scenario(const config &scenario_cfg)
Definition: manager.cpp:96
#define WRN_NG
Definition: manager.cpp:34
game_events::wmi_manager wml_menu_items_
Definition: manager.hpp:51
std::set< std::string > unit_wml_ids_
Definition: manager.hpp:48
std::function< void(game_events::manager &, handler_ptr &)> event_func_t
Definition: manager.hpp:74
void set_menu_items(const config &cfg)
Sets the current menu items to the "menu_item" children of cfg.
const std::unique_ptr< event_handlers > event_handlers_
Definition: manager.hpp:47
void to_config(config &cfg) const
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:205
Domain specific events.
Definition: action_wml.cpp:87
const std::unique_ptr< game_events::wml_event_pump > pump_
Definition: manager.hpp:50
std::size_t i
Definition: function.cpp:941
void write_events(config &cfg) const
Definition: manager.cpp:136
void add_event_handler(const config &handler, bool is_menu_item=false)
Create an event handler.
Definition: manager.cpp:69
Define the game&#39;s event mechanism.
config & add_child(config_key_type key)
Definition: config.cpp:505
bool might_contain_variables(const std::string &str)
Determines if a string might contain variables to interpolate.
Define the handlers for the game&#39;s events mechanism.
std::vector< std::string > split(const config_attribute_value &val)
Standard logging facilities (interface).
game_events::wml_event_pump & pump()
Definition: manager.cpp:230
std::shared_ptr< event_handler > handler_ptr
Definition: fwd.hpp:25
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
static lg::log_domain log_engine("engine")
void execute_on_events(const std::string &event_id, event_func_t func)
Definition: manager.cpp:162
void add_events(const config::const_child_itors &cfgs, const std::string &type=std::string())
Definition: manager.cpp:116
static lg::log_domain log_event_handler("event_handler")