split game_events::manager code into separate files
This commit is contained in:
parent
60e82d2f70
commit
aff3cb8da5
14 changed files with 613 additions and 448 deletions
|
@ -828,6 +828,8 @@ set(wesnoth-main_SRC
|
||||||
game_events/conditional_wml.cpp
|
game_events/conditional_wml.cpp
|
||||||
game_events/entity_location.cpp
|
game_events/entity_location.cpp
|
||||||
game_events/handlers.cpp
|
game_events/handlers.cpp
|
||||||
|
game_events/manager.cpp
|
||||||
|
game_events/manager_impl.cpp
|
||||||
game_events/menu_item.cpp
|
game_events/menu_item.cpp
|
||||||
game_events/pump.cpp
|
game_events/pump.cpp
|
||||||
game_events/wmi_container.cpp
|
game_events/wmi_container.cpp
|
||||||
|
|
|
@ -300,6 +300,8 @@ wesnoth_sources = Split("""
|
||||||
game_events/conditional_wml.cpp
|
game_events/conditional_wml.cpp
|
||||||
game_events/entity_location.cpp
|
game_events/entity_location.cpp
|
||||||
game_events/handlers.cpp
|
game_events/handlers.cpp
|
||||||
|
game_events/manager.cpp
|
||||||
|
game_events/manager_impl.cpp
|
||||||
game_events/menu_item.cpp
|
game_events/menu_item.cpp
|
||||||
game_events/pump.cpp
|
game_events/pump.cpp
|
||||||
game_events/wmi_container.cpp
|
game_events/wmi_container.cpp
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "global.hpp"
|
#include "global.hpp"
|
||||||
#include "action_wml.hpp"
|
#include "action_wml.hpp"
|
||||||
#include "conditional_wml.hpp"
|
#include "conditional_wml.hpp"
|
||||||
#include "handlers.hpp"
|
#include "manager.hpp"
|
||||||
#include "pump.hpp"
|
#include "pump.hpp"
|
||||||
|
|
||||||
#include "actions/attack.hpp"
|
#include "actions/attack.hpp"
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include "../global.hpp"
|
#include "../global.hpp"
|
||||||
#include "handlers.hpp"
|
#include "handlers.hpp"
|
||||||
|
#include "manager.hpp"
|
||||||
|
#include "manager_impl.hpp"
|
||||||
#include "menu_item.hpp"
|
#include "menu_item.hpp"
|
||||||
#include "pump.hpp"
|
#include "pump.hpp"
|
||||||
|
|
||||||
|
@ -50,333 +52,6 @@ static lg::log_domain log_event_handler("event_handler");
|
||||||
// This file is in the game_events namespace.
|
// This file is in the game_events namespace.
|
||||||
namespace game_events {
|
namespace game_events {
|
||||||
|
|
||||||
//t_event_handlers is essentially the implementation details of the manager
|
|
||||||
class manager::t_event_handlers {
|
|
||||||
typedef boost::unordered_map<std::string, handler_list> map_t;
|
|
||||||
typedef boost::unordered_map<std::string, boost::weak_ptr<event_handler> > id_map_t;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef handler_vec::iterator iterator;
|
|
||||||
typedef handler_vec::const_iterator const_iterator;
|
|
||||||
|
|
||||||
private:
|
|
||||||
handler_vec active_; /// Active event handlers. Will not have elements removed unless the t_event_handlers is clear()ed.
|
|
||||||
map_t by_name_; /// Active event handlers with fixed event names, organized by event name.
|
|
||||||
handler_list dynamic_; /// Active event handlers with variables in their event names.
|
|
||||||
id_map_t id_map_; /// Allows quick locating of handlers by id.
|
|
||||||
|
|
||||||
|
|
||||||
void log_handlers();
|
|
||||||
/// Utility to standardize the event names used in by_name_.
|
|
||||||
static std::string standardize_name(const std::string & name);
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef handler_vec::size_type size_type;
|
|
||||||
|
|
||||||
t_event_handlers()
|
|
||||||
: active_()
|
|
||||||
, by_name_()
|
|
||||||
, dynamic_()
|
|
||||||
, id_map_()
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// Read-only access to the handlers with varying event names.
|
|
||||||
const handler_list & get() const { return dynamic_; }
|
|
||||||
/// Read-only access to the handlers with fixed event names, by event name.
|
|
||||||
const handler_list & get(const std::string & name) const;
|
|
||||||
|
|
||||||
/// Adds an event handler.
|
|
||||||
void add_event_handler(const config & cfg, manager & man, bool is_menu_item=false);
|
|
||||||
/// Removes an event handler, identified by its ID.
|
|
||||||
void remove_event_handler(std::string const & id);
|
|
||||||
|
|
||||||
iterator begin() { return active_.begin(); }
|
|
||||||
const_iterator begin() const { return active_.begin(); }
|
|
||||||
|
|
||||||
iterator end() { return active_.end(); }
|
|
||||||
const_iterator end() const { return active_.end(); }
|
|
||||||
|
|
||||||
/// The number of active event handlers.
|
|
||||||
size_type size() const { return active_.size(); }
|
|
||||||
/// Access to active event handlers by index.
|
|
||||||
handler_ptr & operator[](size_type index) { return active_[index]; }
|
|
||||||
};//t_event_handlers
|
|
||||||
|
|
||||||
void manager::t_event_handlers::log_handlers()
|
|
||||||
{
|
|
||||||
if(lg::debug.dont_log("event_handler")) return;
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
BOOST_FOREACH( const handler_ptr & h, active_ ) {
|
|
||||||
if ( !h )
|
|
||||||
continue;
|
|
||||||
const config& cfg = h->get_config();
|
|
||||||
ss << "name=" << cfg["name"] << ", with id=" << cfg["id"] << "; ";
|
|
||||||
}
|
|
||||||
DBG_EH << "active handlers are now " << ss.str() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility to standardize the event names used in by_name_.
|
|
||||||
* This means stripping leading and trailing spaces, and converting internal
|
|
||||||
* spaces to underscores.
|
|
||||||
*/
|
|
||||||
std::string manager::t_event_handlers::standardize_name(const std::string & name)
|
|
||||||
{
|
|
||||||
std::string retval;
|
|
||||||
size_t name_index = 0;
|
|
||||||
size_t name_size = name.size();
|
|
||||||
|
|
||||||
// Trim trailing spaces off the name.
|
|
||||||
while ( name_size > 0 && name[name_size-1] == ' ' )
|
|
||||||
--name_size ;
|
|
||||||
|
|
||||||
// Trim leading spaces off the name.
|
|
||||||
while ( name_index < name_size && name[name_index] == ' ' )
|
|
||||||
++name_index;
|
|
||||||
|
|
||||||
// Copy the rest, converting any remaining spaces to underscores.
|
|
||||||
retval.reserve(name_size - name_index);
|
|
||||||
while ( name_index < name_size ) {
|
|
||||||
char c = name[name_index++];
|
|
||||||
retval.push_back(c == ' ' ? '_' : c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read-only access to the handlers with fixed event names, by event name.
|
|
||||||
*/
|
|
||||||
const handler_list & manager::t_event_handlers::get(const std::string & name) const
|
|
||||||
{
|
|
||||||
// Empty list for the "not found" case.
|
|
||||||
static const handler_list empty_list;
|
|
||||||
|
|
||||||
// Look for the name in the name map.
|
|
||||||
map_t::const_iterator find_it = by_name_.find(standardize_name(name));
|
|
||||||
return find_it == by_name_.end() ? empty_list : find_it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an event handler.
|
|
||||||
* An event with a nonempty ID will not be added if an event with that
|
|
||||||
* ID already exists.
|
|
||||||
*/
|
|
||||||
void manager::t_event_handlers::add_event_handler(const config & cfg, manager & man, bool is_menu_item)
|
|
||||||
{
|
|
||||||
const std::string name = cfg["name"];
|
|
||||||
std::string id = cfg["id"];
|
|
||||||
|
|
||||||
if(!id.empty()) {
|
|
||||||
// Ignore this handler if there is already one with this ID.
|
|
||||||
id_map_t::iterator find_it = id_map_.find(id);
|
|
||||||
if ( find_it != id_map_.end() && !find_it->second.expired() ) {
|
|
||||||
DBG_EH << "ignoring event handler for name='" << name
|
|
||||||
<< "' with id '" << id << "'\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new handler.
|
|
||||||
DBG_EH << "inserting event handler for name=" << name <<
|
|
||||||
" with id=" << id << "\n";
|
|
||||||
handler_ptr new_handler(new event_handler(cfg, is_menu_item, active_.size(), man));
|
|
||||||
active_.push_back(new_handler);
|
|
||||||
|
|
||||||
// File by name.
|
|
||||||
if ( utils::might_contain_variables(name) )
|
|
||||||
dynamic_.push_back(new_handler);
|
|
||||||
else {
|
|
||||||
std::vector<std::string> name_list = utils::split(name);
|
|
||||||
BOOST_FOREACH( const std::string & single_name, name_list )
|
|
||||||
by_name_[standardize_name(single_name)].push_back(new_handler);
|
|
||||||
}
|
|
||||||
// File by ID.
|
|
||||||
if ( !id.empty() )
|
|
||||||
id_map_[id] = new_handler;
|
|
||||||
|
|
||||||
log_handlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an event handler, identified by its ID.
|
|
||||||
* Events with empty IDs cannot be removed.
|
|
||||||
*/
|
|
||||||
void manager::t_event_handlers::remove_event_handler(std::string const & id)
|
|
||||||
{
|
|
||||||
if ( id.empty() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
DBG_EH << "removing event handler with id " << id << "\n";
|
|
||||||
|
|
||||||
// Find the existing handler with this ID.
|
|
||||||
id_map_t::iterator find_it = id_map_.find(id);
|
|
||||||
if ( find_it != id_map_.end() ) {
|
|
||||||
handler_ptr handler = find_it->second.lock();
|
|
||||||
// Remove handler.
|
|
||||||
if ( handler )
|
|
||||||
handler->disable();
|
|
||||||
id_map_.erase(find_it); // Do this even if the lock failed.
|
|
||||||
// The index by name will self-adjust later. No need to adjust it now.
|
|
||||||
}
|
|
||||||
|
|
||||||
log_handlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create an event handler. */
|
|
||||||
void manager::add_event_handler(const config & handler, bool is_menu_item)
|
|
||||||
{
|
|
||||||
event_handlers_->add_event_handler(handler, *this, is_menu_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an item has been used.
|
|
||||||
* (An empty id will never be considered used.)
|
|
||||||
*/
|
|
||||||
bool manager::item_used(const std::string & id)
|
|
||||||
{
|
|
||||||
return !id.empty() && used_items_.count(id) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Records if an item has been used. */
|
|
||||||
void manager::item_used(const std::string & id, bool used)
|
|
||||||
{
|
|
||||||
// Empty IDs are not tracked.
|
|
||||||
if ( id.empty() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( used )
|
|
||||||
used_items_.insert(id);
|
|
||||||
else
|
|
||||||
used_items_.erase(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removes an event handler. */
|
|
||||||
void manager::remove_event_handler(const std::string & id)
|
|
||||||
{
|
|
||||||
event_handlers_->remove_event_handler(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ** manager ** */
|
|
||||||
|
|
||||||
manager::manager(const config& cfg)
|
|
||||||
: event_handlers_(new t_event_handlers())
|
|
||||||
, unit_wml_ids_()
|
|
||||||
, used_items_()
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(const config &ev, cfg.child_range("event")) {
|
|
||||||
add_event_handler(ev);
|
|
||||||
}
|
|
||||||
BOOST_FOREACH(const std::string &id, utils::split(cfg["unit_wml_ids"])) {
|
|
||||||
unit_wml_ids_.insert(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guard against a memory leak (now) / memory corruption (when this is deleted).
|
|
||||||
// This is why creating multiple manager objects is prohibited.
|
|
||||||
assert(resources::lua_kernel != NULL);
|
|
||||||
|
|
||||||
wml_action::map::const_iterator action_end = wml_action::end();
|
|
||||||
wml_action::map::const_iterator action_cur = wml_action::begin();
|
|
||||||
for ( ; action_cur != action_end; ++action_cur ) {
|
|
||||||
resources::lua_kernel->set_wml_action(action_cur->first, action_cur->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string used = cfg["used_items"];
|
|
||||||
if(!used.empty()) {
|
|
||||||
const std::vector<std::string>& v = utils::split(used);
|
|
||||||
for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
|
||||||
item_used(*i, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the event handlers for menu items.
|
|
||||||
resources::gamedata->get_wml_menu_items().init_handlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
manager::~manager() {
|
|
||||||
clear_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ** manager::iteration ** */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event-specific constructor.
|
|
||||||
* This iteration will go through all event handlers matching the given name
|
|
||||||
* (including those defined via menu items).
|
|
||||||
* An empty @a event_name will automatically match nothing.
|
|
||||||
*/
|
|
||||||
manager::iteration::iteration(const std::string & event_name, manager & man) :
|
|
||||||
main_list_(man.event_handlers_->get(event_name)),
|
|
||||||
var_list_(man.event_handlers_->get()),
|
|
||||||
event_name_(event_name),
|
|
||||||
end_(man.event_handlers_->size()),
|
|
||||||
current_is_known_(false),
|
|
||||||
main_is_current_(false),
|
|
||||||
main_it_(main_list_.begin()),
|
|
||||||
var_it_(event_name.empty() ? var_list_.end() : var_list_.begin())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment
|
|
||||||
* Incrementing guarantees that the next dereference will differ from the
|
|
||||||
* previous derference (unless the iteration is exhausted). However, multiple
|
|
||||||
* increments between dereferences are allowed to have the same effect as a
|
|
||||||
* single increment.
|
|
||||||
*/
|
|
||||||
manager::iteration & manager::iteration::operator++()
|
|
||||||
{
|
|
||||||
if ( !current_is_known_ )
|
|
||||||
// Either *this has never been dereferenced, or we already incremented
|
|
||||||
// since the last dereference. We are allowed to ignore this increment.
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
// Guarantee a different element next dereference.
|
|
||||||
if ( main_is_current_ )
|
|
||||||
++main_it_;
|
|
||||||
else
|
|
||||||
++var_it_; // (We'll check for a name match when we dereference.)
|
|
||||||
|
|
||||||
// We no longer know which list is current.
|
|
||||||
current_is_known_ = false;
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dereference
|
|
||||||
* Will return a null pointer when the end of the iteration is reached.
|
|
||||||
*/
|
|
||||||
handler_ptr manager::iteration::operator*()
|
|
||||||
{
|
|
||||||
// Get the candidate for the current element from the main list.
|
|
||||||
handler_ptr main_ptr = *main_it_;
|
|
||||||
handler_vec::size_type main_index = ptr_index(main_ptr);
|
|
||||||
|
|
||||||
// Get the candidate for the current element from the var list.
|
|
||||||
handler_ptr var_ptr = *var_it_;
|
|
||||||
// (Loop while var_ptr would be chosen over main_ptr, but the name does not match.)
|
|
||||||
while ( var_ptr && var_ptr->index() < main_index &&
|
|
||||||
!var_ptr->matches_name(event_name_) )
|
|
||||||
var_ptr = *++var_it_;
|
|
||||||
handler_vec::size_type var_index = ptr_index(var_ptr);
|
|
||||||
|
|
||||||
// Which list? (Index ties go to the main list.)
|
|
||||||
current_is_known_ = main_index < end_ || var_index < end_;
|
|
||||||
main_is_current_ = main_index <= var_index;
|
|
||||||
|
|
||||||
if ( !current_is_known_ )
|
|
||||||
return handler_ptr(); // End of list; return a null pointer.
|
|
||||||
else
|
|
||||||
return main_is_current_ ? main_ptr : var_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ** handler_list::iterator ** */
|
/* ** handler_list::iterator ** */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -520,35 +195,5 @@ bool event_handler::matches_name(const std::string &name) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void manager::add_events(const config::const_child_itors &cfgs, const std::string& type)
|
|
||||||
{
|
|
||||||
if(!type.empty()) {
|
|
||||||
if(std::find(unit_wml_ids_.begin(),unit_wml_ids_.end(),type) != unit_wml_ids_.end()) return;
|
|
||||||
unit_wml_ids_.insert(type);
|
|
||||||
}
|
|
||||||
BOOST_FOREACH(const config &new_ev, cfgs) {
|
|
||||||
if(type.empty() && new_ev["id"].empty())
|
|
||||||
{
|
|
||||||
WRN_NG << "attempt to add an [event] with empty id=, ignoring " << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
add_event_handler(new_ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void manager::write_events(config& cfg)
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(const handler_ptr &eh, *event_handlers_) {
|
|
||||||
if ( !eh || eh->is_menu_item() ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cfg.add_child("event", eh->get_config());
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg["used_items"] = utils::join(used_items_);
|
|
||||||
cfg["unit_wml_ids"] = utils::join(unit_wml_ids_);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace game_events
|
} // end namespace game_events
|
||||||
|
|
||||||
|
|
|
@ -142,92 +142,6 @@ namespace game_events
|
||||||
/// The actual list.
|
/// The actual list.
|
||||||
list_t data_;
|
list_t data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// The game event manager loads the scenario configuration object,
|
|
||||||
/// and ensures that events are handled according to the
|
|
||||||
/// scenario configuration for its lifetime.
|
|
||||||
///
|
|
||||||
/// Thus, a manager object should be created when a scenario is played,
|
|
||||||
/// and destroyed at the end of the scenario.
|
|
||||||
/// If a second manager object is created before destroying the previous
|
|
||||||
/// one, the game will crash with an assertion failure.
|
|
||||||
class manager : boost::noncopyable {
|
|
||||||
public:
|
|
||||||
/// This class is similar to an input iterator through event handlers,
|
|
||||||
/// except each instance knows its own end (determined when constructed).
|
|
||||||
/// Subsequent dereferences are not guaranteed to return the same element,
|
|
||||||
/// so it is important to assign a dereference to a variable if you want
|
|
||||||
/// to use it more than once. On the other hand, a dereference will not
|
|
||||||
/// return a null pointer until the end of the iteration is reached (and
|
|
||||||
/// this is how to detect the end of the iteration).
|
|
||||||
///
|
|
||||||
/// For simplicity, this class is neither assignable nor equality
|
|
||||||
/// comparable nor default constructable, and there is no postincrement.
|
|
||||||
/// Typedefs are also skipped.
|
|
||||||
class iteration
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Event-specific constructor.
|
|
||||||
explicit iteration(const std::string & event_name, manager &);
|
|
||||||
|
|
||||||
// Increment:
|
|
||||||
iteration & operator++();
|
|
||||||
// Dereference:
|
|
||||||
handler_ptr operator*();
|
|
||||||
|
|
||||||
private: // functions
|
|
||||||
/// Gets the index from a pointer, capped at end_.
|
|
||||||
handler_vec::size_type ptr_index(const handler_ptr & ptr) const
|
|
||||||
{ return !bool(ptr) ? end_ : std::min(ptr->index(), end_); }
|
|
||||||
|
|
||||||
private: // data
|
|
||||||
/// The fixed-name event handlers for this iteration.
|
|
||||||
const handler_list & main_list_;
|
|
||||||
/// The varying-name event handlers for this iteration.
|
|
||||||
const handler_list & var_list_;
|
|
||||||
/// The event name for this iteration.
|
|
||||||
const std::string event_name_;
|
|
||||||
/// The end of this iteration. We intentionally exclude handlers
|
|
||||||
/// added after *this is constructed.
|
|
||||||
const handler_vec::size_type end_;
|
|
||||||
|
|
||||||
/// Set to true upon dereferencing.
|
|
||||||
bool current_is_known_;
|
|
||||||
/// true if the most recent dereference was taken from main_list_.
|
|
||||||
bool main_is_current_;
|
|
||||||
/// The current (or next) element from main_list_.
|
|
||||||
handler_list::iterator main_it_;
|
|
||||||
/// The current (or next) element from var_list_.
|
|
||||||
handler_list::iterator var_it_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class t_event_handlers;
|
|
||||||
|
|
||||||
boost::scoped_ptr<t_event_handlers> event_handlers_;
|
|
||||||
std::set<std::string> unit_wml_ids_;
|
|
||||||
std::set<std::string> used_items_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// Note that references will be maintained,
|
|
||||||
/// and must remain valid for the life of the object.
|
|
||||||
explicit manager(const config& scenario_cfg);
|
|
||||||
~manager();
|
|
||||||
|
|
||||||
/// Create an event handler.
|
|
||||||
void add_event_handler(const config & handler, bool is_menu_item=false);
|
|
||||||
/// Checks if an item has been used.
|
|
||||||
bool item_used(const std::string & id);
|
|
||||||
/// Records if an item has been used.
|
|
||||||
void item_used(const std::string & id, bool used);
|
|
||||||
/// Removes an event handler.
|
|
||||||
void remove_event_handler(const std::string & id);
|
|
||||||
|
|
||||||
void add_events(const config::const_child_itors &cfgs,
|
|
||||||
const std::string& type = std::string());
|
|
||||||
void write_events(config& cfg);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // GAME_EVENTS_HANDLERS_H_INCLUDED
|
#endif // GAME_EVENTS_HANDLERS_H_INCLUDED
|
||||||
|
|
230
src/game_events/manager.cpp
Normal file
230
src/game_events/manager.cpp
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||||
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.hpp"
|
||||||
|
|
||||||
|
#include "game_events/manager.hpp"
|
||||||
|
|
||||||
|
#include "handlers.hpp"
|
||||||
|
#include "manager_impl.hpp"
|
||||||
|
#include "menu_item.hpp"
|
||||||
|
#include "pump.hpp"
|
||||||
|
|
||||||
|
#include "formula_string_utils.hpp"
|
||||||
|
#include "game_data.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "reports.hpp"
|
||||||
|
#include "resources.hpp"
|
||||||
|
#include "scripting/game_lua_kernel.hpp"
|
||||||
|
#include "serialization/string_utils.hpp"
|
||||||
|
#include "soundsource.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
static lg::log_domain log_engine("engine");
|
||||||
|
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||||
|
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||||
|
#define WRN_NG LOG_STREAM(warn, log_engine)
|
||||||
|
|
||||||
|
static lg::log_domain log_event_handler("event_handler");
|
||||||
|
#define DBG_EH LOG_STREAM(debug, log_event_handler)
|
||||||
|
|
||||||
|
namespace game_events {
|
||||||
|
|
||||||
|
/** Create an event handler. */
|
||||||
|
void manager::add_event_handler(const config & handler, bool is_menu_item)
|
||||||
|
{
|
||||||
|
event_handlers_->add_event_handler(handler, *this, is_menu_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an item has been used.
|
||||||
|
* (An empty id will never be considered used.)
|
||||||
|
*/
|
||||||
|
bool manager::item_used(const std::string & id)
|
||||||
|
{
|
||||||
|
return !id.empty() && used_items_.count(id) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Records if an item has been used. */
|
||||||
|
void manager::item_used(const std::string & id, bool used)
|
||||||
|
{
|
||||||
|
// Empty IDs are not tracked.
|
||||||
|
if ( id.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( used )
|
||||||
|
used_items_.insert(id);
|
||||||
|
else
|
||||||
|
used_items_.erase(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes an event handler. */
|
||||||
|
void manager::remove_event_handler(const std::string & id)
|
||||||
|
{
|
||||||
|
event_handlers_->remove_event_handler(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ** manager ** */
|
||||||
|
|
||||||
|
manager::manager(const config& cfg)
|
||||||
|
: event_handlers_(new t_event_handlers())
|
||||||
|
, unit_wml_ids_()
|
||||||
|
, used_items_()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const config &ev, cfg.child_range("event")) {
|
||||||
|
add_event_handler(ev);
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const std::string &id, utils::split(cfg["unit_wml_ids"])) {
|
||||||
|
unit_wml_ids_.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guard against a memory leak (now) / memory corruption (when this is deleted).
|
||||||
|
// This is why creating multiple manager objects is prohibited.
|
||||||
|
assert(resources::lua_kernel != NULL);
|
||||||
|
|
||||||
|
wml_action::map::const_iterator action_end = wml_action::end();
|
||||||
|
wml_action::map::const_iterator action_cur = wml_action::begin();
|
||||||
|
for ( ; action_cur != action_end; ++action_cur ) {
|
||||||
|
resources::lua_kernel->set_wml_action(action_cur->first, action_cur->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string used = cfg["used_items"];
|
||||||
|
if(!used.empty()) {
|
||||||
|
const std::vector<std::string>& v = utils::split(used);
|
||||||
|
for(std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||||
|
item_used(*i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the event handlers for menu items.
|
||||||
|
resources::gamedata->get_wml_menu_items().init_handlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
manager::~manager() {
|
||||||
|
clear_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ** manager::iteration ** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event-specific constructor.
|
||||||
|
* This iteration will go through all event handlers matching the given name
|
||||||
|
* (including those defined via menu items).
|
||||||
|
* An empty @a event_name will automatically match nothing.
|
||||||
|
*/
|
||||||
|
manager::iteration::iteration(const std::string & event_name, manager & man) :
|
||||||
|
main_list_(man.event_handlers_->get(event_name)),
|
||||||
|
var_list_(man.event_handlers_->get()),
|
||||||
|
event_name_(event_name),
|
||||||
|
end_(man.event_handlers_->size()),
|
||||||
|
current_is_known_(false),
|
||||||
|
main_is_current_(false),
|
||||||
|
main_it_(main_list_.begin()),
|
||||||
|
var_it_(event_name.empty() ? var_list_.end() : var_list_.begin())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment
|
||||||
|
* Incrementing guarantees that the next dereference will differ from the
|
||||||
|
* previous derference (unless the iteration is exhausted). However, multiple
|
||||||
|
* increments between dereferences are allowed to have the same effect as a
|
||||||
|
* single increment.
|
||||||
|
*/
|
||||||
|
manager::iteration & manager::iteration::operator++()
|
||||||
|
{
|
||||||
|
if ( !current_is_known_ )
|
||||||
|
// Either *this has never been dereferenced, or we already incremented
|
||||||
|
// since the last dereference. We are allowed to ignore this increment.
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
// Guarantee a different element next dereference.
|
||||||
|
if ( main_is_current_ )
|
||||||
|
++main_it_;
|
||||||
|
else
|
||||||
|
++var_it_; // (We'll check for a name match when we dereference.)
|
||||||
|
|
||||||
|
// We no longer know which list is current.
|
||||||
|
current_is_known_ = false;
|
||||||
|
|
||||||
|
// Done.
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dereference
|
||||||
|
* Will return a null pointer when the end of the iteration is reached.
|
||||||
|
*/
|
||||||
|
handler_ptr manager::iteration::operator*()
|
||||||
|
{
|
||||||
|
// Get the candidate for the current element from the main list.
|
||||||
|
handler_ptr main_ptr = *main_it_;
|
||||||
|
handler_vec::size_type main_index = ptr_index(main_ptr);
|
||||||
|
|
||||||
|
// Get the candidate for the current element from the var list.
|
||||||
|
handler_ptr var_ptr = *var_it_;
|
||||||
|
// (Loop while var_ptr would be chosen over main_ptr, but the name does not match.)
|
||||||
|
while ( var_ptr && var_ptr->index() < main_index &&
|
||||||
|
!var_ptr->matches_name(event_name_) )
|
||||||
|
var_ptr = *++var_it_;
|
||||||
|
handler_vec::size_type var_index = ptr_index(var_ptr);
|
||||||
|
|
||||||
|
// Which list? (Index ties go to the main list.)
|
||||||
|
current_is_known_ = main_index < end_ || var_index < end_;
|
||||||
|
main_is_current_ = main_index <= var_index;
|
||||||
|
|
||||||
|
if ( !current_is_known_ )
|
||||||
|
return handler_ptr(); // End of list; return a null pointer.
|
||||||
|
else
|
||||||
|
return main_is_current_ ? main_ptr : var_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void manager::add_events(const config::const_child_itors &cfgs, const std::string& type)
|
||||||
|
{
|
||||||
|
if(!type.empty()) {
|
||||||
|
if(std::find(unit_wml_ids_.begin(),unit_wml_ids_.end(),type) != unit_wml_ids_.end()) return;
|
||||||
|
unit_wml_ids_.insert(type);
|
||||||
|
}
|
||||||
|
BOOST_FOREACH(const config &new_ev, cfgs) {
|
||||||
|
if(type.empty() && new_ev["id"].empty())
|
||||||
|
{
|
||||||
|
WRN_NG << "attempt to add an [event] with empty id=, ignoring " << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
add_event_handler(new_ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void manager::write_events(config& cfg)
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const handler_ptr &eh, *event_handlers_) {
|
||||||
|
if ( !eh || eh->is_menu_item() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cfg.add_child("event", eh->get_config());
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg["used_items"] = utils::join(used_items_);
|
||||||
|
cfg["unit_wml_ids"] = utils::join(unit_wml_ids_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end namespace game_events
|
116
src/game_events/manager.hpp
Normal file
116
src/game_events/manager.hpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||||
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GAME_EVENTS_MANAGER_HPP
|
||||||
|
#define GAME_EVENTS_MANAGER_HPP
|
||||||
|
|
||||||
|
#include "game_events/handlers.hpp"
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class game_lua_kernel;
|
||||||
|
|
||||||
|
namespace game_events {
|
||||||
|
|
||||||
|
class t_event_handlers;
|
||||||
|
|
||||||
|
/// The game event manager loads the scenario configuration object,
|
||||||
|
/// and ensures that events are handled according to the
|
||||||
|
/// scenario configuration for its lifetime.
|
||||||
|
///
|
||||||
|
/// Thus, a manager object should be created when a scenario is played,
|
||||||
|
/// and destroyed at the end of the scenario.
|
||||||
|
/// If a second manager object is created before destroying the previous
|
||||||
|
/// one, the game will crash with an assertion failure.
|
||||||
|
class manager : boost::noncopyable {
|
||||||
|
public:
|
||||||
|
/// This class is similar to an input iterator through event handlers,
|
||||||
|
/// except each instance knows its own end (determined when constructed).
|
||||||
|
/// Subsequent dereferences are not guaranteed to return the same element,
|
||||||
|
/// so it is important to assign a dereference to a variable if you want
|
||||||
|
/// to use it more than once. On the other hand, a dereference will not
|
||||||
|
/// return a null pointer until the end of the iteration is reached (and
|
||||||
|
/// this is how to detect the end of the iteration).
|
||||||
|
///
|
||||||
|
/// For simplicity, this class is neither assignable nor equality
|
||||||
|
/// comparable nor default constructable, and there is no postincrement.
|
||||||
|
/// Typedefs are also skipped.
|
||||||
|
class iteration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Event-specific constructor.
|
||||||
|
explicit iteration(const std::string & event_name, manager &);
|
||||||
|
|
||||||
|
// Increment:
|
||||||
|
iteration & operator++();
|
||||||
|
// Dereference:
|
||||||
|
handler_ptr operator*();
|
||||||
|
|
||||||
|
private: // functions
|
||||||
|
/// Gets the index from a pointer, capped at end_.
|
||||||
|
handler_vec::size_type ptr_index(const handler_ptr & ptr) const
|
||||||
|
{ return !bool(ptr) ? end_ : std::min(ptr->index(), end_); }
|
||||||
|
|
||||||
|
private: // data
|
||||||
|
/// The fixed-name event handlers for this iteration.
|
||||||
|
const handler_list & main_list_;
|
||||||
|
/// The varying-name event handlers for this iteration.
|
||||||
|
const handler_list & var_list_;
|
||||||
|
/// The event name for this iteration.
|
||||||
|
const std::string event_name_;
|
||||||
|
/// The end of this iteration. We intentionally exclude handlers
|
||||||
|
/// added after *this is constructed.
|
||||||
|
const handler_vec::size_type end_;
|
||||||
|
|
||||||
|
/// Set to true upon dereferencing.
|
||||||
|
bool current_is_known_;
|
||||||
|
/// true if the most recent dereference was taken from main_list_.
|
||||||
|
bool main_is_current_;
|
||||||
|
/// The current (or next) element from main_list_.
|
||||||
|
handler_list::iterator main_it_;
|
||||||
|
/// The current (or next) element from var_list_.
|
||||||
|
handler_list::iterator var_it_;
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::scoped_ptr<t_event_handlers> event_handlers_;
|
||||||
|
std::set<std::string> unit_wml_ids_;
|
||||||
|
std::set<std::string> used_items_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Note that references will be maintained,
|
||||||
|
/// and must remain valid for the life of the object.
|
||||||
|
explicit manager(const config& scenario_cfg);
|
||||||
|
~manager();
|
||||||
|
|
||||||
|
/// Create an event handler.
|
||||||
|
void add_event_handler(const config & handler, bool is_menu_item=false);
|
||||||
|
/// Checks if an item has been used.
|
||||||
|
bool item_used(const std::string & id);
|
||||||
|
/// Records if an item has been used.
|
||||||
|
void item_used(const std::string & id, bool used);
|
||||||
|
/// Removes an event handler.
|
||||||
|
void remove_event_handler(const std::string & id);
|
||||||
|
|
||||||
|
void add_events(const config::const_child_itors &cfgs,
|
||||||
|
const std::string& type = std::string());
|
||||||
|
void write_events(config& cfg);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
170
src/game_events/manager_impl.cpp
Normal file
170
src/game_events/manager_impl.cpp
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||||
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "game_events/manager_impl.hpp"
|
||||||
|
|
||||||
|
#include "game_events/handlers.hpp"
|
||||||
|
#include "game_events/manager.hpp"
|
||||||
|
#include "game_events/menu_item.hpp"
|
||||||
|
#include "game_events/pump.hpp"
|
||||||
|
|
||||||
|
#include "formula_string_utils.hpp"
|
||||||
|
#include "game_data.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "reports.hpp"
|
||||||
|
#include "resources.hpp"
|
||||||
|
#include "scripting/game_lua_kernel.hpp"
|
||||||
|
#include "serialization/string_utils.hpp"
|
||||||
|
#include "soundsource.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
static lg::log_domain log_engine("engine");
|
||||||
|
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||||
|
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||||
|
#define WRN_NG LOG_STREAM(warn, log_engine)
|
||||||
|
|
||||||
|
static lg::log_domain log_event_handler("event_handler");
|
||||||
|
#define DBG_EH LOG_STREAM(debug, log_event_handler)
|
||||||
|
|
||||||
|
namespace game_events {
|
||||||
|
|
||||||
|
void t_event_handlers::log_handlers()
|
||||||
|
{
|
||||||
|
if(lg::debug.dont_log("event_handler")) return;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
BOOST_FOREACH( const handler_ptr & h, active_ ) {
|
||||||
|
if ( !h )
|
||||||
|
continue;
|
||||||
|
const config& cfg = h->get_config();
|
||||||
|
ss << "name=" << cfg["name"] << ", with id=" << cfg["id"] << "; ";
|
||||||
|
}
|
||||||
|
DBG_EH << "active handlers are now " << ss.str() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to standardize the event names used in by_name_.
|
||||||
|
* This means stripping leading and trailing spaces, and converting internal
|
||||||
|
* spaces to underscores.
|
||||||
|
*/
|
||||||
|
std::string t_event_handlers::standardize_name(const std::string & name)
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
size_t name_index = 0;
|
||||||
|
size_t name_size = name.size();
|
||||||
|
|
||||||
|
// Trim trailing spaces off the name.
|
||||||
|
while ( name_size > 0 && name[name_size-1] == ' ' )
|
||||||
|
--name_size ;
|
||||||
|
|
||||||
|
// Trim leading spaces off the name.
|
||||||
|
while ( name_index < name_size && name[name_index] == ' ' )
|
||||||
|
++name_index;
|
||||||
|
|
||||||
|
// Copy the rest, converting any remaining spaces to underscores.
|
||||||
|
retval.reserve(name_size - name_index);
|
||||||
|
while ( name_index < name_size ) {
|
||||||
|
char c = name[name_index++];
|
||||||
|
retval.push_back(c == ' ' ? '_' : c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read-only access to the handlers with fixed event names, by event name.
|
||||||
|
*/
|
||||||
|
const handler_list & t_event_handlers::get(const std::string & name) const
|
||||||
|
{
|
||||||
|
// Empty list for the "not found" case.
|
||||||
|
static const handler_list empty_list;
|
||||||
|
|
||||||
|
// Look for the name in the name map.
|
||||||
|
map_t::const_iterator find_it = by_name_.find(standardize_name(name));
|
||||||
|
return find_it == by_name_.end() ? empty_list : find_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an event handler.
|
||||||
|
* An event with a nonempty ID will not be added if an event with that
|
||||||
|
* ID already exists.
|
||||||
|
*/
|
||||||
|
void t_event_handlers::add_event_handler(const config & cfg, manager & man, bool is_menu_item)
|
||||||
|
{
|
||||||
|
const std::string name = cfg["name"];
|
||||||
|
std::string id = cfg["id"];
|
||||||
|
|
||||||
|
if(!id.empty()) {
|
||||||
|
// Ignore this handler if there is already one with this ID.
|
||||||
|
id_map_t::iterator find_it = id_map_.find(id);
|
||||||
|
if ( find_it != id_map_.end() && !find_it->second.expired() ) {
|
||||||
|
DBG_EH << "ignoring event handler for name='" << name
|
||||||
|
<< "' with id '" << id << "'\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new handler.
|
||||||
|
DBG_EH << "inserting event handler for name=" << name <<
|
||||||
|
" with id=" << id << "\n";
|
||||||
|
handler_ptr new_handler(new event_handler(cfg, is_menu_item, active_.size(), man));
|
||||||
|
active_.push_back(new_handler);
|
||||||
|
|
||||||
|
// File by name.
|
||||||
|
if ( utils::might_contain_variables(name) )
|
||||||
|
dynamic_.push_back(new_handler);
|
||||||
|
else {
|
||||||
|
std::vector<std::string> name_list = utils::split(name);
|
||||||
|
BOOST_FOREACH( const std::string & single_name, name_list )
|
||||||
|
by_name_[standardize_name(single_name)].push_back(new_handler);
|
||||||
|
}
|
||||||
|
// File by ID.
|
||||||
|
if ( !id.empty() )
|
||||||
|
id_map_[id] = new_handler;
|
||||||
|
|
||||||
|
log_handlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an event handler, identified by its ID.
|
||||||
|
* Events with empty IDs cannot be removed.
|
||||||
|
*/
|
||||||
|
void t_event_handlers::remove_event_handler(std::string const & id)
|
||||||
|
{
|
||||||
|
if ( id.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
DBG_EH << "removing event handler with id " << id << "\n";
|
||||||
|
|
||||||
|
// Find the existing handler with this ID.
|
||||||
|
id_map_t::iterator find_it = id_map_.find(id);
|
||||||
|
if ( find_it != id_map_.end() ) {
|
||||||
|
handler_ptr handler = find_it->second.lock();
|
||||||
|
// Remove handler.
|
||||||
|
if ( handler )
|
||||||
|
handler->disable();
|
||||||
|
id_map_.erase(find_it); // Do this even if the lock failed.
|
||||||
|
// The index by name will self-adjust later. No need to adjust it now.
|
||||||
|
}
|
||||||
|
|
||||||
|
log_handlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace game_events
|
82
src/game_events/manager_impl.hpp
Normal file
82
src/game_events/manager_impl.hpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||||
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GAME_EVENTS_MANAGER_IMPL_HPP
|
||||||
|
#define GAME_EVENTS_MANAGER_IMPL_HPP
|
||||||
|
|
||||||
|
#include "game_events/handlers.hpp"
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/weak_ptr.hpp>
|
||||||
|
|
||||||
|
namespace game_events {
|
||||||
|
|
||||||
|
//t_event_handlers is essentially the implementation details of the manager
|
||||||
|
class t_event_handlers {
|
||||||
|
typedef boost::unordered_map<std::string, handler_list> map_t;
|
||||||
|
typedef boost::unordered_map<std::string, boost::weak_ptr<event_handler> > id_map_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef handler_vec::iterator iterator;
|
||||||
|
typedef handler_vec::const_iterator const_iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
handler_vec active_; /// Active event handlers. Will not have elements removed unless the t_event_handlers is clear()ed.
|
||||||
|
map_t by_name_; /// Active event handlers with fixed event names, organized by event name.
|
||||||
|
handler_list dynamic_; /// Active event handlers with variables in their event names.
|
||||||
|
id_map_t id_map_; /// Allows quick locating of handlers by id.
|
||||||
|
|
||||||
|
|
||||||
|
void log_handlers();
|
||||||
|
/// Utility to standardize the event names used in by_name_.
|
||||||
|
static std::string standardize_name(const std::string & name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef handler_vec::size_type size_type;
|
||||||
|
|
||||||
|
t_event_handlers()
|
||||||
|
: active_()
|
||||||
|
, by_name_()
|
||||||
|
, dynamic_()
|
||||||
|
, id_map_()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// Read-only access to the handlers with varying event names.
|
||||||
|
const handler_list & get() const { return dynamic_; }
|
||||||
|
/// Read-only access to the handlers with fixed event names, by event name.
|
||||||
|
const handler_list & get(const std::string & name) const;
|
||||||
|
|
||||||
|
/// Adds an event handler.
|
||||||
|
void add_event_handler(const config & cfg, manager & man, bool is_menu_item=false);
|
||||||
|
/// Removes an event handler, identified by its ID.
|
||||||
|
void remove_event_handler(std::string const & id);
|
||||||
|
|
||||||
|
iterator begin() { return active_.begin(); }
|
||||||
|
const_iterator begin() const { return active_.begin(); }
|
||||||
|
|
||||||
|
iterator end() { return active_.end(); }
|
||||||
|
const_iterator end() const { return active_.end(); }
|
||||||
|
|
||||||
|
/// The number of active event handlers.
|
||||||
|
size_type size() const { return active_.size(); }
|
||||||
|
/// Access to active event handlers by index.
|
||||||
|
handler_ptr & operator[](size_type index) { return active_[index]; }
|
||||||
|
};//t_event_handlers
|
||||||
|
|
||||||
|
} //end namespace game_events
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,10 +17,13 @@
|
||||||
* Definitions for a class that implements WML-defined (right-click) menu items.
|
* Definitions for a class that implements WML-defined (right-click) menu items.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../global.hpp"
|
|
||||||
#include "menu_item.hpp"
|
#include "menu_item.hpp"
|
||||||
|
|
||||||
|
#include "../global.hpp"
|
||||||
|
|
||||||
#include "conditional_wml.hpp"
|
#include "conditional_wml.hpp"
|
||||||
#include "handlers.hpp"
|
#include "handlers.hpp"
|
||||||
|
#include "manager.hpp"
|
||||||
#include "pump.hpp"
|
#include "pump.hpp"
|
||||||
|
|
||||||
#include "../actions/undo.hpp"
|
#include "../actions/undo.hpp"
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "pump.hpp"
|
#include "pump.hpp"
|
||||||
#include "conditional_wml.hpp"
|
#include "conditional_wml.hpp"
|
||||||
#include "handlers.hpp"
|
#include "handlers.hpp"
|
||||||
|
#include "manager.hpp"
|
||||||
|
|
||||||
#include "../display_chat_manager.hpp"
|
#include "../display_chat_manager.hpp"
|
||||||
#include "../game_config.hpp"
|
#include "../game_config.hpp"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "dialogs.hpp"
|
#include "dialogs.hpp"
|
||||||
#include "display_chat_manager.hpp"
|
#include "display_chat_manager.hpp"
|
||||||
#include "formula_string_utils.hpp"
|
#include "formula_string_utils.hpp"
|
||||||
#include "game_events/handlers.hpp"
|
#include "game_events/manager.hpp"
|
||||||
#include "game_events/menu_item.hpp"
|
#include "game_events/menu_item.hpp"
|
||||||
#include "game_events/pump.hpp"
|
#include "game_events/pump.hpp"
|
||||||
#include "game_preferences.hpp"
|
#include "game_preferences.hpp"
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "display_chat_manager.hpp"
|
#include "display_chat_manager.hpp"
|
||||||
#include "game_end_exceptions.hpp"
|
#include "game_end_exceptions.hpp"
|
||||||
#include "game_errors.hpp" //needed to be thrown
|
#include "game_errors.hpp" //needed to be thrown
|
||||||
#include "game_events/handlers.hpp"
|
#include "game_events/manager.hpp"
|
||||||
#include "game_events/pump.hpp"
|
#include "game_events/pump.hpp"
|
||||||
#include "gettext.hpp"
|
#include "gettext.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "game_data.hpp"
|
#include "game_data.hpp"
|
||||||
#include "game_config.hpp" // for add_color_info, etc
|
#include "game_config.hpp" // for add_color_info, etc
|
||||||
#include "game_errors.hpp" // for game_error
|
#include "game_errors.hpp" // for game_error
|
||||||
#include "game_events/handlers.hpp" // for add_events
|
#include "game_events/manager.hpp" // for add_events
|
||||||
#include "game_preferences.hpp" // for encountered_units
|
#include "game_preferences.hpp" // for encountered_units
|
||||||
#include "gettext.hpp" // for N_
|
#include "gettext.hpp" // for N_
|
||||||
#include "log.hpp" // for LOG_STREAM, logger, etc
|
#include "log.hpp" // for LOG_STREAM, logger, etc
|
||||||
|
|
Loading…
Add table
Reference in a new issue