Refactor static_wml_actions as class wml_action.

It's a bit more C++-like, but more importantly puts related static
variables in the same file (so this should cure the static
initialization fiasco known as bug #21020).
This commit is contained in:
JaMiT 2013-08-12 21:42:01 -05:00
parent b4b957128c
commit cab1c823b8
8 changed files with 55 additions and 35 deletions

View File

@ -85,6 +85,11 @@ static lg::log_domain log_config("config");
namespace game_events namespace game_events
{ {
// This must be defined before any WML actions are.
// (So keep it at the rop of this file?)
wml_action::map wml_action::registry_;
namespace { // advance declarations namespace { // advance declarations
std::string get_caption(const vconfig& cfg, unit_map::iterator speaker); std::string get_caption(const vconfig& cfg, unit_map::iterator speaker);
std::string get_image(const vconfig& cfg, unit_map::iterator speaker); std::string get_image(const vconfig& cfg, unit_map::iterator speaker);
@ -592,6 +597,18 @@ void handle_wml_log_message(const config& cfg)
} }
/**
* Using this constructor for a static object outside action_wml.cpp
* will likely lead to a static initialization fiasco.
* @param[in] tag The WML tag for this action.
* @param[in] function The callback for this action.
*/
wml_action::wml_action(const std::string & tag, handler function)
{
registry_[tag] = function;
}
/** /**
* WML_HANDLER_FUNCTION macro handles auto registration for wml handlers * WML_HANDLER_FUNCTION macro handles auto registration for wml handlers
* *
@ -612,11 +629,8 @@ void handle_wml_log_message(const config& cfg)
* *
* Generated code looks like this: * Generated code looks like this:
* \code * \code
* void wml_action_foo(...); * void wml_func_foo(...);
* struct wml_func_register_foo { * static wml_action wml_action_foo("foo", &wml_func_foo);
* wml_func_register_foo() {
* register_action("foo", &wml_func_foo);
* } wml_func_register_foo;
* void wml_func_foo(...) * void wml_func_foo(...)
* { * {
* // code for foo * // code for foo
@ -625,12 +639,7 @@ void handle_wml_log_message(const config& cfg)
*/ */
#define WML_HANDLER_FUNCTION(pname, pei, pcfg) \ #define WML_HANDLER_FUNCTION(pname, pei, pcfg) \
static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \ static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \
struct wml_func_register_##pname \ static wml_action wml_action_##pname(#pname, &wml_func_##pname); \
{ \
wml_func_register_##pname() \
{ register_action(#pname, &wml_func_##pname); } \
}; \
static wml_func_register_##pname wml_func_register_##pname##_aux; \
static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg) static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg)

View File

@ -29,6 +29,7 @@
class config; class config;
struct map_location; struct map_location;
class vconfig;
namespace t_translation { namespace t_translation {
struct t_terrain; struct t_terrain;
@ -37,8 +38,31 @@ namespace t_translation {
namespace game_events namespace game_events
{ {
struct queued_event;
// Most of the functionality in the source file is accessed via callbacks, // Most of the functionality in the source file is accessed via callbacks,
// registered with register_action(). // accessed by iterating over wml_action.
class wml_action {
public:
typedef void (*handler)(const queued_event &, const vconfig &);
typedef std::map<std::string, handler> map;
/// Using this constructor for a static object outside action_wml.cpp
/// will likely lead to a static initialization fiasco.
wml_action(const std::string & tag, handler function);
/// The first registered action.
static map::const_iterator begin() { return registry_.begin(); }
/// One past the last registered action.
static map::const_iterator end() { return registry_.end(); }
private:
/// Tracks the known action handlers.
static map registry_;
};
/** /**
* Changes a terrain location. * Changes a terrain location.

View File

@ -48,7 +48,6 @@ static lg::log_domain log_event_handler("event_handler");
namespace game_events { namespace game_events {
namespace { // Types namespace { // Types
typedef std::map<std::string, wml_handler_function> static_wml_action_map;
typedef std::pair< std::string, config* > wmi_command_change; typedef std::pair< std::string, config* > wmi_command_change;
class t_event_handlers { class t_event_handlers {
@ -215,7 +214,6 @@ namespace { // Types
namespace { // Variables namespace { // Variables
t_event_handlers event_handlers; t_event_handlers event_handlers;
/** Map of the default action handlers known of the engine. */ /** Map of the default action handlers known of the engine. */
static_wml_action_map static_wml_actions;
std::set<std::string> unit_wml_ids; std::set<std::string> unit_wml_ids;
std::set<std::string> used_items; std::set<std::string> used_items;
std::vector< wmi_command_change > wmi_command_changes; std::vector< wmi_command_change > wmi_command_changes;
@ -294,12 +292,6 @@ void item_used(const std::string & id, bool used)
used_items.erase(id); used_items.erase(id);
} }
/** Registers a standard action handler. */
void register_action(const std::string & tag, wml_handler_function handler)
{
static_wml_actions[tag] = handler;
}
/** Removes a pending menu item command change. */ /** Removes a pending menu item command change. */
void remove_wmi_change(const std::string & id) void remove_wmi_change(const std::string & id)
{ {
@ -338,8 +330,10 @@ manager::manager(const config& cfg)
resources::lua_kernel = new LuaKernel(cfg); resources::lua_kernel = new LuaKernel(cfg);
running_ = true; running_ = true;
BOOST_FOREACH(static_wml_action_map::value_type &action, static_wml_actions) { wml_action::map::const_iterator action_end = wml_action::end();
resources::lua_kernel->set_wml_action(action.first, action.second); 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"]; const std::string used = cfg["used_items"];

View File

@ -27,18 +27,12 @@
#include "../config.hpp" #include "../config.hpp"
#include "../variable.hpp" #include "../variable.hpp"
class vconfig;
namespace game_events namespace game_events
{ {
struct queued_event; struct queued_event;
typedef void (*wml_handler_function)(const queued_event &event_info,
const vconfig &cfg);
typedef void (*action_handler)(const queued_event &, const vconfig &);
class event_handler class event_handler
{ {
public: public:
@ -104,8 +98,6 @@ namespace game_events
bool item_used(const std::string & id); bool item_used(const std::string & id);
/// Records if an item has been used. /// Records if an item has been used.
void item_used(const std::string & id, bool used); void item_used(const std::string & id, bool used);
/// Registers a standard action handler.
void register_action(const std::string & tag, wml_handler_function handler);
/// Removes an event handler. /// Removes an event handler.
void remove_event_handler(const std::string & id); void remove_event_handler(const std::string & id);
/// Removes a pending menu item command change. /// Removes a pending menu item command change.

View File

@ -21,6 +21,7 @@
#include "../global.hpp" #include "../global.hpp"
#include "pump.hpp" #include "pump.hpp"
#include "conditional_wml.hpp" #include "conditional_wml.hpp"
#include "handlers.hpp"
#include "../game_config.hpp" #include "../game_config.hpp"
#include "../game_display.hpp" #include "../game_display.hpp"

View File

@ -40,7 +40,6 @@
#include "attack_prediction.hpp" #include "attack_prediction.hpp"
#include "filesystem.hpp" #include "filesystem.hpp"
#include "game_display.hpp" #include "game_display.hpp"
#include "game_events/action_wml.hpp"
#include "game_events/conditional_wml.hpp" #include "game_events/conditional_wml.hpp"
#include "game_events/pump.hpp" #include "game_events/pump.hpp"
#include "game_preferences.hpp" #include "game_preferences.hpp"
@ -4454,7 +4453,7 @@ LuaKernel::~LuaKernel()
*/ */
static int cfun_wml_action(lua_State *L) static int cfun_wml_action(lua_State *L)
{ {
game_events::action_handler h = reinterpret_cast<game_events::action_handler> game_events::wml_action::handler h = reinterpret_cast<game_events::wml_action::handler>
(lua_touserdata(L, lua_upvalueindex(1))); (lua_touserdata(L, lua_upvalueindex(1)));
vconfig vcfg = luaW_checkvconfig(L, 1); vconfig vcfg = luaW_checkvconfig(L, 1);
@ -4465,7 +4464,7 @@ static int cfun_wml_action(lua_State *L)
/** /**
* Registers a function for use as an action handler. * Registers a function for use as an action handler.
*/ */
void LuaKernel::set_wml_action(std::string const &cmd, game_events::action_handler h) void LuaKernel::set_wml_action(std::string const &cmd, game_events::wml_action::handler h)
{ {
lua_State *L = mState; lua_State *L = mState;

View File

@ -15,7 +15,7 @@
#ifndef SCRIPTING_LUA_HPP #ifndef SCRIPTING_LUA_HPP
#define SCRIPTING_LUA_HPP #define SCRIPTING_LUA_HPP
#include "game_events/handlers.hpp" #include "game_events/action_wml.hpp"
class unit; class unit;
struct lua_State; struct lua_State;
@ -44,7 +44,7 @@ public:
void save_game(config &); void save_game(config &);
void load_game(); void load_game();
bool run_event(game_events::queued_event const &); bool run_event(game_events::queued_event const &);
void set_wml_action(std::string const &, game_events::action_handler); void set_wml_action(std::string const &, game_events::wml_action::handler);
bool run_wml_action(std::string const &, vconfig const &, bool run_wml_action(std::string const &, vconfig const &,
game_events::queued_event const &); game_events::queued_event const &);
bool run_filter(char const *name, unit const &u); bool run_filter(char const *name, unit const &u);

View File

@ -23,6 +23,7 @@
#include "callable_objects.hpp" #include "callable_objects.hpp"
#include "formula.hpp" #include "formula.hpp"
#include "game_display.hpp" #include "game_display.hpp"
#include "game_events/handlers.hpp"
#include "game_preferences.hpp" #include "game_preferences.hpp"
#include "gamestatus.hpp" #include "gamestatus.hpp"
#include "gettext.hpp" #include "gettext.hpp"