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
{
// 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
std::string get_caption(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
*
@ -612,11 +629,8 @@ void handle_wml_log_message(const config& cfg)
*
* Generated code looks like this:
* \code
* void wml_action_foo(...);
* struct wml_func_register_foo {
* wml_func_register_foo() {
* register_action("foo", &wml_func_foo);
* } wml_func_register_foo;
* void wml_func_foo(...);
* static wml_action wml_action_foo("foo", &wml_func_foo);
* void wml_func_foo(...)
* {
* // code for foo
@ -625,12 +639,7 @@ void handle_wml_log_message(const config& cfg)
*/
#define WML_HANDLER_FUNCTION(pname, pei, pcfg) \
static void wml_func_##pname(const queued_event &pei, const vconfig &pcfg); \
struct wml_func_register_##pname \
{ \
wml_func_register_##pname() \
{ register_action(#pname, &wml_func_##pname); } \
}; \
static wml_func_register_##pname wml_func_register_##pname##_aux; \
static wml_action wml_action_##pname(#pname, &wml_func_##pname); \
static void wml_func_##pname(const queued_event& pei, const vconfig& pcfg)

View file

@ -29,6 +29,7 @@
class config;
struct map_location;
class vconfig;
namespace t_translation {
struct t_terrain;
@ -37,8 +38,31 @@ namespace t_translation {
namespace game_events
{
struct queued_event;
// 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.

View file

@ -48,7 +48,6 @@ static lg::log_domain log_event_handler("event_handler");
namespace game_events {
namespace { // Types
typedef std::map<std::string, wml_handler_function> static_wml_action_map;
typedef std::pair< std::string, config* > wmi_command_change;
class t_event_handlers {
@ -215,7 +214,6 @@ namespace { // Types
namespace { // Variables
t_event_handlers event_handlers;
/** 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> used_items;
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);
}
/** 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. */
void remove_wmi_change(const std::string & id)
{
@ -338,8 +330,10 @@ manager::manager(const config& cfg)
resources::lua_kernel = new LuaKernel(cfg);
running_ = true;
BOOST_FOREACH(static_wml_action_map::value_type &action, static_wml_actions) {
resources::lua_kernel->set_wml_action(action.first, action.second);
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"];

View file

@ -27,18 +27,12 @@
#include "../config.hpp"
#include "../variable.hpp"
class vconfig;
namespace game_events
{
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
{
public:
@ -104,8 +98,6 @@ namespace game_events
bool item_used(const std::string & id);
/// Records if an item has been 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.
void remove_event_handler(const std::string & id);
/// Removes a pending menu item command change.

View file

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

View file

@ -40,7 +40,6 @@
#include "attack_prediction.hpp"
#include "filesystem.hpp"
#include "game_display.hpp"
#include "game_events/action_wml.hpp"
#include "game_events/conditional_wml.hpp"
#include "game_events/pump.hpp"
#include "game_preferences.hpp"
@ -4454,7 +4453,7 @@ LuaKernel::~LuaKernel()
*/
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)));
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.
*/
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;

View file

@ -15,7 +15,7 @@
#ifndef SCRIPTING_LUA_HPP
#define SCRIPTING_LUA_HPP
#include "game_events/handlers.hpp"
#include "game_events/action_wml.hpp"
class unit;
struct lua_State;
@ -44,7 +44,7 @@ public:
void save_game(config &);
void load_game();
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 &,
game_events::queued_event const &);
bool run_filter(char const *name, unit const &u);

View file

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