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"
26 
27 #include <iostream>
28 
29 static lg::log_domain log_engine("engine");
30 #define DBG_NG LOG_STREAM(debug, log_engine)
31 #define LOG_NG LOG_STREAM(info, log_engine)
32 #define WRN_NG LOG_STREAM(warn, log_engine)
33 
34 static lg::log_domain log_event_handler("event_handler");
35 #define DBG_EH LOG_STREAM(debug, log_event_handler)
36 
37 namespace
38 {
39 // Event handlers can't be destroyed as long as at least one of these locks exist.
40 class event_handler_list_lock
41 {
42 public:
43  event_handler_list_lock()
44  {
45  ++num_locks_;
46  }
47 
48  ~event_handler_list_lock()
49  {
50  --num_locks_;
51  }
52 
53  static bool none()
54  {
55  return num_locks_ == 0u;
56  }
57 
58 private:
59  static unsigned int num_locks_;
60 };
61 
62 unsigned int event_handler_list_lock::num_locks_ = 0u;
63 } // namespace
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 
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  // Ensure that event handlers won't be cleaned up while we're iterating them.
173  event_handler_list_lock lock;
174 
175  for(unsigned i = 0; i < saved_end; ++i) {
176  handler_ptr handler = nullptr;
177 
178  try {
179  handler = active_handlers.at(i);
180  } catch(const std::out_of_range&) {
181  continue;
182  }
183 
184  // Shouldn't happen, but we're just being safe.
185  if(!handler || handler->disabled()) {
186  continue;
187  }
188 
189  // Could be more than one.
190  for(const std::string& name : handler->names()) {
191  bool matches = false;
192 
194  // If we don't have gamedata, we can't interpolate variables, so there's
195  // no way the name will match. Move on to the next one in that case.
196  if(!gd) {
197  continue;
198  }
199 
200  matches = standardized_event_id ==
202  } else {
203  matches = standardized_event_id == name;
204  }
205 
206  if(matches) {
207  func(*this, handler);
208  break;
209  }
210  }
211  }
212  }
213 
214  // Clean up expired ptrs. This saves us effort later since it ensures every ptr is valid.
215  if(event_handler_list_lock::none()) {
216  event_handlers_->clean_up_expired_handlers(standardized_event_id);
217  }
218 }
219 
221 {
222  // If there is an event handler list lock, an event is being processed.
223  return !event_handler_list_lock::none();
224 }
225 
227 {
228  return *pump_;
229 }
230 
231 } // 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:220
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_.
static help_manager manager
The help manager.
Definition: help.cpp:34
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.
void read_scenario(const config &scenario_cfg)
Definition: manager.cpp:95
const t_string name
#define WRN_NG
Definition: manager.cpp:32
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:210
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:479
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.
Standard logging facilities (interface).
game_events::wml_event_pump & pump()
Definition: manager.cpp:226
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:68
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")