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