Track lua event listener count, and let the C++ host know.

This allows completely avoiding the call overhead if there
are none. The downside is that the event object now has to
be a userdata with lots of metamethods.
develop
Alexander Gavrilov 2012-08-23 19:27:12 +04:00
parent 7046a6abbc
commit c6c5ad56c9
7 changed files with 268 additions and 62 deletions

@ -1448,8 +1448,8 @@ Core context specific functions:
Event type Event type
---------- ----------
An event is just a lua table with a predefined metatable that An event is a native object transparently wrapping a lua table,
contains a __call metamethod. When it is invoked, it loops and implementing a __call metamethod. When it is invoked, it loops
through the table with next and calls all contained values. through the table with next and calls all contained values.
This is intended as an extensible way to add listeners. This is intended as an extensible way to add listeners.
@ -1464,10 +1464,18 @@ Features:
* ``event[key] = function`` * ``event[key] = function``
Sets the function as one of the listeners. Sets the function as one of the listeners. Assign *nil* to remove it.
**NOTE**: The ``df.NULL`` key is reserved for the use by **NOTE**: The ``df.NULL`` key is reserved for the use by
the C++ owner of the event, and has some special semantics. the C++ owner of the event; it is an error to try setting it.
* ``#event``
Returns the number of non-nil listeners.
* ``pairs(event)``
Iterates over all listeners in the table.
* ``event(args...)`` * ``event(args...)``

@ -1596,8 +1596,8 @@ Using <tt class="docutils literal">timeout_active(id,nil)</tt> cancels the timer
</ul> </ul>
<div class="section" id="event-type"> <div class="section" id="event-type">
<h3><a class="toc-backref" href="#id29">Event type</a></h3> <h3><a class="toc-backref" href="#id29">Event type</a></h3>
<p>An event is just a lua table with a predefined metatable that <p>An event is a native object transparently wrapping a lua table,
contains a __call metamethod. When it is invoked, it loops and implementing a __call metamethod. When it is invoked, it loops
through the table with next and calls all contained values. through the table with next and calls all contained values.
This is intended as an extensible way to add listeners.</p> This is intended as an extensible way to add listeners.</p>
<p>This type itself is available in any context, but only the <p>This type itself is available in any context, but only the
@ -1608,9 +1608,15 @@ core context has the actual events defined by C++ code.</p>
<p>Creates a new instance of an event.</p> <p>Creates a new instance of an event.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">event[key] = function</tt></p> <li><p class="first"><tt class="docutils literal">event[key] = function</tt></p>
<p>Sets the function as one of the listeners.</p> <p>Sets the function as one of the listeners. Assign <em>nil</em> to remove it.</p>
<p><strong>NOTE</strong>: The <tt class="docutils literal">df.NULL</tt> key is reserved for the use by <p><strong>NOTE</strong>: The <tt class="docutils literal">df.NULL</tt> key is reserved for the use by
the C++ owner of the event, and has some special semantics.</p> the C++ owner of the event; it is an error to try setting it.</p>
</li>
<li><p class="first"><tt class="docutils literal">#event</tt></p>
<p>Returns the number of non-nil listeners.</p>
</li>
<li><p class="first"><tt class="docutils literal">pairs(event)</tt></p>
<p>Iterates over all listeners in the table.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal"><span class="pre">event(args...)</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">event(args...)</span></tt></p>
<p>Invokes all listeners contained in the event in an arbitrary <p>Invokes all listeners contained in the event in an arbitrary

@ -68,6 +68,11 @@ lua_State *DFHack::Lua::Core::State = NULL;
void dfhack_printerr(lua_State *S, const std::string &str); void dfhack_printerr(lua_State *S, const std::string &str);
inline bool is_null_userdata(lua_State *L, int idx)
{
return lua_islightuserdata(L, idx) && !lua_touserdata(L, idx);
}
inline void AssertCoreSuspend(lua_State *state) inline void AssertCoreSuspend(lua_State *state)
{ {
assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended()); assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended());
@ -1244,14 +1249,123 @@ static const luaL_Reg dfhack_coro_funcs[] = {
static int DFHACK_EVENT_META_TOKEN = 0; static int DFHACK_EVENT_META_TOKEN = 0;
int DFHack::Lua::NewEvent(lua_State *state) namespace {
struct EventObject {
int item_count;
Lua::Event::Owner *owner;
};
}
void DFHack::Lua::Event::New(lua_State *state, Owner *owner)
{ {
lua_newtable(state); auto obj = (EventObject *)lua_newuserdata(state, sizeof(EventObject));
obj->item_count = 0;
obj->owner = owner;
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_EVENT_META_TOKEN); lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_EVENT_META_TOKEN);
lua_setmetatable(state, -2); lua_setmetatable(state, -2);
lua_newtable(state);
lua_setuservalue(state, -2);
}
void DFHack::Lua::Event::SetPrivateCallback(lua_State *L, int event)
{
lua_getuservalue(L, event);
lua_swap(L);
lua_rawsetp(L, -2, NULL);
lua_pop(L, 1);
}
static int dfhack_event_new(lua_State *L)
{
Lua::Event::New(L);
return 1; return 1;
} }
static int dfhack_event_len(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
auto obj = (EventObject *)lua_touserdata(L, 1);
lua_pushinteger(L, obj->item_count);
return 1;
}
static int dfhack_event_tostring(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
auto obj = (EventObject *)lua_touserdata(L, 1);
lua_pushfstring(L, "<event: %d listeners>", obj->item_count);
return 1;
}
static int dfhack_event_index(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_getuservalue(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
return 1;
}
static int dfhack_event_next(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_getuservalue(L, 1);
lua_pushvalue(L, 2);
while (lua_next(L, -2))
{
if (is_null_userdata(L, -2))
lua_pop(L, 1);
else
return 2;
}
lua_pushnil(L);
return 1;
}
static int dfhack_event_pairs(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_pushcfunction(L, dfhack_event_next);
lua_pushvalue(L, 1);
lua_pushnil(L);
return 3;
}
static int dfhack_event_newindex(lua_State *L)
{
luaL_checktype(L, 1, LUA_TUSERDATA);
if (is_null_userdata(L, 2))
luaL_argerror(L, 2, "Key NULL is reserved in events.");
lua_settop(L, 3);
lua_getuservalue(L, 1);
bool new_nil = lua_isnil(L, 3);
lua_pushvalue(L, 2);
lua_rawget(L, 4);
bool old_nil = lua_isnil(L, -1);
lua_settop(L, 4);
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_rawset(L, 4);
int delta = 0;
if (old_nil && !new_nil) delta = 1;
else if (new_nil && !old_nil) delta = -1;
if (delta != 0)
{
auto obj = (EventObject *)lua_touserdata(L, 1);
obj->item_count += delta;
if (obj->owner)
obj->owner->on_count_changed(obj->item_count, delta);
}
return 0;
}
static void do_invoke_event(lua_State *L, int argbase, int num_args, int errorfun) static void do_invoke_event(lua_State *L, int argbase, int num_args, int errorfun)
{ {
for (int i = 0; i < num_args; i++) for (int i = 0; i < num_args; i++)
@ -1292,7 +1406,7 @@ static void dfhack_event_invoke(lua_State *L, int base, bool from_c)
while (lua_next(L, event)) while (lua_next(L, event))
{ {
// Skip the NULL key in the main loop // Skip the NULL key in the main loop
if (lua_islightuserdata(L, -2) && !lua_touserdata(L, -2)) if (is_null_userdata(L, -2))
lua_pop(L, 1); lua_pop(L, 1);
else else
do_invoke_event(L, argbase, num_args, errorfun); do_invoke_event(L, argbase, num_args, errorfun);
@ -1303,14 +1417,20 @@ static void dfhack_event_invoke(lua_State *L, int base, bool from_c)
static int dfhack_event_call(lua_State *state) static int dfhack_event_call(lua_State *state)
{ {
luaL_checktype(state, 1, LUA_TTABLE); luaL_checktype(state, 1, LUA_TUSERDATA);
luaL_checkstack(state, lua_gettop(state)+2, "stack overflow in event dispatch"); luaL_checkstack(state, lua_gettop(state)+2, "stack overflow in event dispatch");
auto obj = (EventObject *)lua_touserdata(state, 1);
if (obj->owner)
obj->owner->on_invoked(state, lua_gettop(state)-1, false);
lua_getuservalue(state, 1);
lua_replace(state, 1);
dfhack_event_invoke(state, 0, false); dfhack_event_invoke(state, 0, false);
return 0; return 0;
} }
void DFHack::Lua::InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args) void DFHack::Lua::Event::Invoke(color_ostream &out, lua_State *state, void *key, int num_args)
{ {
AssertCoreSuspend(state); AssertCoreSuspend(state);
@ -1325,7 +1445,7 @@ void DFHack::Lua::InvokeEvent(color_ostream &out, lua_State *state, void *key, i
lua_rawgetp(state, LUA_REGISTRYINDEX, key); lua_rawgetp(state, LUA_REGISTRYINDEX, key);
if (!lua_istable(state, -1)) if (!lua_isuserdata(state, -1))
{ {
if (!lua_isnil(state, -1)) if (!lua_isnil(state, -1))
out.printerr("Invalid event object in Lua::InvokeEvent"); out.printerr("Invalid event object in Lua::InvokeEvent");
@ -1333,22 +1453,29 @@ void DFHack::Lua::InvokeEvent(color_ostream &out, lua_State *state, void *key, i
return; return;
} }
auto obj = (EventObject *)lua_touserdata(state, -1);
lua_insert(state, base+1); lua_insert(state, base+1);
if (obj->owner)
obj->owner->on_invoked(state, num_args, true);
lua_getuservalue(state, base+1);
lua_replace(state, base+1);
color_ostream *cur_out = Lua::GetOutput(state); color_ostream *cur_out = Lua::GetOutput(state);
set_dfhack_output(state, &out); set_dfhack_output(state, &out);
dfhack_event_invoke(state, base, true); dfhack_event_invoke(state, base, true);
set_dfhack_output(state, cur_out); set_dfhack_output(state, cur_out);
} }
void DFHack::Lua::MakeEvent(lua_State *state, void *key) void DFHack::Lua::Event::Make(lua_State *state, void *key, Owner *owner)
{ {
lua_rawgetp(state, LUA_REGISTRYINDEX, key); lua_rawgetp(state, LUA_REGISTRYINDEX, key);
if (lua_isnil(state, -1)) if (lua_isnil(state, -1))
{ {
lua_pop(state, 1); lua_pop(state, 1);
NewEvent(state); New(state, owner);
} }
lua_dup(state); lua_dup(state);
@ -1358,7 +1485,7 @@ void DFHack::Lua::MakeEvent(lua_State *state, void *key)
void DFHack::Lua::Notification::invoke(color_ostream &out, int nargs) void DFHack::Lua::Notification::invoke(color_ostream &out, int nargs)
{ {
assert(state); assert(state);
InvokeEvent(out, state, key, nargs); Event::Invoke(out, state, key, nargs);
} }
void DFHack::Lua::Notification::bind(lua_State *state, void *key) void DFHack::Lua::Notification::bind(lua_State *state, void *key)
@ -1369,12 +1496,12 @@ void DFHack::Lua::Notification::bind(lua_State *state, void *key)
void DFHack::Lua::Notification::bind(lua_State *state, const char *name) void DFHack::Lua::Notification::bind(lua_State *state, const char *name)
{ {
MakeEvent(state, this); Event::Make(state, this);
if (handler) if (handler)
{ {
PushFunctionWrapper(state, 0, name, handler); PushFunctionWrapper(state, 0, name, handler);
lua_rawsetp(state, -2, NULL); Event::SetPrivateCallback(state, -2);
} }
this->state = state; this->state = state;
@ -1435,11 +1562,26 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
lua_newtable(state); lua_newtable(state);
lua_pushcfunction(state, dfhack_event_call); lua_pushcfunction(state, dfhack_event_call);
lua_setfield(state, -2, "__call"); lua_setfield(state, -2, "__call");
lua_pushcfunction(state, Lua::NewEvent); lua_pushcfunction(state, dfhack_event_len);
lua_setfield(state, -2, "new"); lua_setfield(state, -2, "__len");
lua_pushcfunction(state, dfhack_event_tostring);
lua_setfield(state, -2, "__tostring");
lua_pushcfunction(state, dfhack_event_index);
lua_setfield(state, -2, "__index");
lua_pushcfunction(state, dfhack_event_newindex);
lua_setfield(state, -2, "__newindex");
lua_pushcfunction(state, dfhack_event_pairs);
lua_setfield(state, -2, "__pairs");
lua_dup(state); lua_dup(state);
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_EVENT_META_TOKEN); lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_EVENT_META_TOKEN);
lua_setfield(state, -2, "event");
lua_newtable(state);
lua_pushcfunction(state, dfhack_event_new);
lua_setfield(state, -2, "new");
lua_dup(state);
lua_setfield(state, -3, "__metatable");
lua_setfield(state, -3, "event");
lua_pop(state, 1);
// Initialize the dfhack global // Initialize the dfhack global
luaL_setfuncs(state, dfhack_funcs, 0); luaL_setfuncs(state, dfhack_funcs, 0);
@ -1599,7 +1741,7 @@ void DFHack::Lua::Core::onStateChange(color_ostream &out, int code) {
} }
Lua::Push(State, code); Lua::Push(State, code);
Lua::InvokeEvent(out, State, (void*)onStateChange, 1); Lua::Event::Invoke(out, State, (void*)onStateChange, 1);
} }
static void run_timers(color_ostream &out, lua_State *L, static void run_timers(color_ostream &out, lua_State *L,
@ -1653,7 +1795,7 @@ void DFHack::Lua::Core::Init(color_ostream &out)
// Register events // Register events
lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN); lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
MakeEvent(State, (void*)onStateChange); Event::Make(State, (void*)onStateChange);
lua_setfield(State, -2, "onStateChange"); lua_setfield(State, -2, "onStateChange");
lua_pushcfunction(State, dfhack_timeout); lua_pushcfunction(State, dfhack_timeout);

@ -108,6 +108,50 @@ struct Plugin::RefAutoinc
~RefAutoinc(){ lock->lock_sub(); }; ~RefAutoinc(){ lock->lock_sub(); };
}; };
struct Plugin::LuaCommand {
Plugin *owner;
std::string name;
int (*command)(lua_State *state);
LuaCommand(Plugin *owner, std::string name)
: owner(owner), name(name), command(NULL) {}
};
struct Plugin::LuaFunction {
Plugin *owner;
std::string name;
function_identity_base *identity;
bool silent;
LuaFunction(Plugin *owner, std::string name)
: owner(owner), name(name), identity(NULL), silent(false) {}
};
struct Plugin::LuaEvent : public Lua::Event::Owner {
LuaFunction handler;
Lua::Notification *event;
bool active;
int count;
LuaEvent(Plugin *owner, std::string name)
: handler(owner,name), event(NULL), active(false), count(0)
{
handler.silent = true;
}
void on_count_changed(int new_cnt, int delta) {
RefAutoinc lock(handler.owner->access);
count = new_cnt;
if (event)
event->on_count_changed(new_cnt, delta);
}
void on_invoked(lua_State *state, int nargs, bool from_c) {
RefAutoinc lock(handler.owner->access);
if (event)
event->on_invoked(state, nargs, from_c);
}
};
Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm) Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm)
{ {
filename = filepath; filename = filepath;
@ -439,7 +483,11 @@ void Plugin::index_lua(DFLibrary *lib)
cmd->handler.identity = evlist->event->get_handler(); cmd->handler.identity = evlist->event->get_handler();
cmd->event = evlist->event; cmd->event = evlist->event;
if (cmd->active) if (cmd->active)
{
cmd->event->bind(Lua::Core::State, cmd); cmd->event->bind(Lua::Core::State, cmd);
if (cmd->count > 0)
cmd->event->on_count_changed(cmd->count, 0);
}
} }
} }
} }
@ -477,8 +525,13 @@ int Plugin::lua_fun_wrapper(lua_State *state)
RefAutoinc lock(cmd->owner->access); RefAutoinc lock(cmd->owner->access);
if (!cmd->identity) if (!cmd->identity)
{
if (cmd->silent)
return 0;
luaL_error(state, "plugin function %s() has been unloaded", luaL_error(state, "plugin function %s() has been unloaded",
(cmd->owner->name+"."+cmd->name).c_str()); (cmd->owner->name+"."+cmd->name).c_str());
}
return LuaWrapper::method_wrapper_core(state, cmd->identity); return LuaWrapper::method_wrapper_core(state, cmd->identity);
} }
@ -506,14 +559,14 @@ void Plugin::open_lua(lua_State *state, int table)
{ {
for (auto it = lua_events.begin(); it != lua_events.end(); ++it) for (auto it = lua_events.begin(); it != lua_events.end(); ++it)
{ {
Lua::MakeEvent(state, it->second); Lua::Event::Make(state, it->second, it->second);
push_function(state, &it->second->handler); push_function(state, &it->second->handler);
lua_rawsetp(state, -2, NULL); Lua::Event::SetPrivateCallback(state, -2);
it->second->active = true; it->second->active = true;
if (it->second->event) if (it->second->event)
it->second->event->bind(state, it->second); it->second->event->bind(Lua::Core::State, it->second);
lua_setfield(state, table, it->first.c_str()); lua_setfield(state, table, it->first.c_str());
} }

@ -310,9 +310,18 @@ namespace DFHack {namespace Lua {
DFHACK_EXPORT bool IsCoreContext(lua_State *state); DFHACK_EXPORT bool IsCoreContext(lua_State *state);
DFHACK_EXPORT int NewEvent(lua_State *state); namespace Event {
DFHACK_EXPORT void MakeEvent(lua_State *state, void *key); struct DFHACK_EXPORT Owner {
DFHACK_EXPORT void InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args); virtual ~Owner() {}
virtual void on_count_changed(int new_cnt, int delta) {}
virtual void on_invoked(lua_State *state, int nargs, bool from_c) {}
};
DFHACK_EXPORT void New(lua_State *state, Owner *owner = NULL);
DFHACK_EXPORT void Make(lua_State *state, void *key, Owner *owner = NULL);
DFHACK_EXPORT void SetPrivateCallback(lua_State *state, int ev_idx);
DFHACK_EXPORT void Invoke(color_ostream &out, lua_State *state, void *key, int num_args);
}
class StackUnwinder { class StackUnwinder {
lua_State *state; lua_State *state;
@ -365,18 +374,24 @@ namespace DFHack {namespace Lua {
} }
} }
class DFHACK_EXPORT Notification { class DFHACK_EXPORT Notification : public Event::Owner {
lua_State *state; lua_State *state;
void *key; void *key;
function_identity_base *handler; function_identity_base *handler;
int count;
public: public:
Notification(function_identity_base *handler = NULL) Notification(function_identity_base *handler = NULL)
: state(NULL), key(NULL), handler(handler) {} : state(NULL), key(NULL), handler(handler), count(0) {}
int get_listener_count() { return count; }
lua_State *get_state() { return state; } lua_State *get_state() { return state; }
function_identity_base *get_handler() { return handler; } function_identity_base *get_handler() { return handler; }
lua_State *state_if_count() { return (count > 0) ? state : NULL; }
void on_count_changed(int new_cnt, int) { count = new_cnt; }
void invoke(color_ostream &out, int nargs); void invoke(color_ostream &out, int nargs);
void bind(lua_State *state, const char *name); void bind(lua_State *state, const char *name);
@ -388,7 +403,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out) { \ void name(color_ostream &out) { \
handler(out); \ handler(out); \
if (name##_event.get_state()) { \ if (name##_event.state_if_count()) { \
name##_event.invoke(out, 0); \ name##_event.invoke(out, 0); \
} \ } \
} }
@ -397,7 +412,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1) { \ void name(color_ostream &out, arg_type1 arg1) { \
handler(out, arg1); \ handler(out, arg1); \
if (auto state = name##_event.get_state()) { \ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \ DFHack::Lua::Push(state, arg1); \
name##_event.invoke(out, 1); \ name##_event.invoke(out, 1); \
} \ } \
@ -407,7 +422,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2) { \ void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2) { \
handler(out, arg1, arg2); \ handler(out, arg1, arg2); \
if (auto state = name##_event.get_state()) { \ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \ DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \ DFHack::Lua::Push(state, arg2); \
name##_event.invoke(out, 2); \ name##_event.invoke(out, 2); \
@ -418,7 +433,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3) { \ void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3) { \
handler(out, arg1, arg2, arg3); \ handler(out, arg1, arg2, arg3); \
if (auto state = name##_event.get_state()) { \ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \ DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \ DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \ DFHack::Lua::Push(state, arg3); \
@ -430,7 +445,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4) { \ void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4) { \
handler(out, arg1, arg2, arg3, arg4); \ handler(out, arg1, arg2, arg3, arg4); \
if (auto state = name##_event.get_state()) { \ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \ DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \ DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \ DFHack::Lua::Push(state, arg3); \
@ -443,7 +458,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \ static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4, arg_type5 arg5) { \ void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4, arg_type5 arg5) { \
handler(out, arg1, arg2, arg3, arg4, arg5); \ handler(out, arg1, arg2, arg3, arg4, arg5); \
if (auto state = name##_event.get_state()) { \ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \ DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \ DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \ DFHack::Lua::Push(state, arg3); \

@ -173,31 +173,16 @@ namespace DFHack
PluginManager * parent; PluginManager * parent;
plugin_state state; plugin_state state;
struct LuaCommand { struct LuaCommand;
Plugin *owner;
std::string name;
int (*command)(lua_State *state);
LuaCommand(Plugin *owner, std::string name) : owner(owner), name(name) {}
};
std::map<std::string, LuaCommand*> lua_commands; std::map<std::string, LuaCommand*> lua_commands;
static int lua_cmd_wrapper(lua_State *state); static int lua_cmd_wrapper(lua_State *state);
struct LuaFunction { struct LuaFunction;
Plugin *owner;
std::string name;
function_identity_base *identity;
LuaFunction(Plugin *owner, std::string name) : owner(owner), name(name) {}
};
std::map<std::string, LuaFunction*> lua_functions; std::map<std::string, LuaFunction*> lua_functions;
static int lua_fun_wrapper(lua_State *state); static int lua_fun_wrapper(lua_State *state);
void push_function(lua_State *state, LuaFunction *fn); void push_function(lua_State *state, LuaFunction *fn);
struct LuaEvent { struct LuaEvent;
LuaFunction handler;
Lua::Notification *event;
bool active;
LuaEvent(Plugin *owner, std::string name) : handler(owner,name), active(false) {}
};
std::map<std::string, LuaEvent*> lua_events; std::map<std::string, LuaEvent*> lua_events;
void index_lua(DFLibrary *lib); void index_lua(DFLibrary *lib);

@ -122,8 +122,9 @@ end
-- Misc functions -- Misc functions
function printall(table) function printall(table)
if type(table) == 'table' or df.isvalid(table) == 'ref' then local ok,f,t,k = pcall(pairs,table)
for k,v in pairs(table) do if ok then
for k,v in f,t,k do
print(string.format("%-23s\t = %s",tostring(k),tostring(v))) print(string.format("%-23s\t = %s",tostring(k),tostring(v)))
end end
end end
@ -177,10 +178,6 @@ end
-- String conversions -- String conversions
function dfhack.event:__tostring()
return "<event>"
end
function dfhack.persistent:__tostring() function dfhack.persistent:__tostring()
return "<persistent "..self.entry_id..":"..self.key.."=\"" return "<persistent "..self.entry_id..":"..self.key.."=\""
..self.value.."\":"..table.concat(self.ints,",")..">" ..self.value.."\":"..table.concat(self.ints,",")..">"