From ae5a27c996e5c245bfb2c915f993ce9adb55cdbf Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 4 Apr 2021 00:53:12 -0400 Subject: [PATCH] Support passing an arbitrary Lua function as the filter when the event is registered from Lua. --- src/game_events/manager.cpp | 1 - src/scripting/game_lua_kernel.cpp | 42 ++++++++++++++++++++++++++++--- src/scripting/game_lua_kernel.hpp | 3 ++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/game_events/manager.cpp b/src/game_events/manager.cpp index 80bd69ad0cf..9821ba1e76c 100644 --- a/src/game_events/manager.cpp +++ b/src/game_events/manager.cpp @@ -72,7 +72,6 @@ void manager::add_event_handler_from_wml(const config& handler, game_lua_kernel& new_handler->read_filters(handler); // Strip out anything that's used by the event system itself. - // TODO: "filter" is a stub intended for Lua code. config args; for(const auto& [attr, val] : handler.attribute_range()) { if(attr == "id" || attr == "name" || attr == "first_time_only" || attr.compare(0, 6, "filter") == 0) { diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index a01bd823245..7bb9fa5076d 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -3691,6 +3691,27 @@ int game_lua_kernel::intf_log_replay(lua_State* L) return 0; } +struct lua_event_filter : public game_events::event_filter +{ + lua_event_filter(game_lua_kernel& lk, int idx, const config& args) : lk(lk), args_(args) + { + ref_ = lk.save_wml_event(idx); + } + bool operator()(const game_events::queued_event& event_info) const override + { + bool result; + return lk.run_wml_event(ref_, args_, event_info, &result) && result; + } + ~lua_event_filter() + { + lk.clear_wml_event(ref_); + } +private: + game_lua_kernel& lk; + int ref_; + vconfig args_; +}; + static std::string read_event_name(lua_State* L, int idx) { if(lua_isstring(L, idx)) { @@ -3751,6 +3772,7 @@ int game_lua_kernel::intf_add_event(lua_State *L) } auto new_handler = man.add_event_handler_from_lua(name, id, repeat, is_menu_item); if(new_handler.valid()) { + bool has_lua_filter = false; new_handler->set_arguments(luaW_table_get_def(L, 1, "content", config{"__empty_lua_event", true})); if(luaW_tableget(L, 1, "filter")) { @@ -3758,7 +3780,9 @@ int game_lua_kernel::intf_add_event(lua_State *L) config filters; if(!luaW_toconfig(L, filterIdx, filters)) { if(lua_isfunction(L, filterIdx)) { - //new_handler->add_filter(std::make_unique()); + int fcnIdx = lua_absindex(L, -1); + new_handler->add_filter(std::make_unique(*this, fcnIdx, luaW_table_get_def(L, 1, "filter_args", config()))); + has_lua_filter = true; } else { if(luaW_tableget(L, filterIdx, "condition")) { filters.add_child("filter_condition", luaW_checkconfig(L, -1)); @@ -3786,6 +3810,11 @@ int game_lua_kernel::intf_add_event(lua_State *L) if(luaW_tableget(L, 1, "action")) { new_handler->set_event_ref(save_wml_event(-1)); } else { + if(has_lua_filter) { + // This just sets the appropriate flags so the engine knows it cannot be serialized. + // The register_wml_event call will override the actual event_ref so just pass LUA_NOREF here. + new_handler->set_event_ref(LUA_NOREF); + } new_handler->register_wml_event(*this); } } @@ -5395,7 +5424,7 @@ void game_lua_kernel::clear_wml_event(int ref) lua_pop(L, 1); } -bool game_lua_kernel::run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev) +bool game_lua_kernel::run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev, bool* out) { lua_State* L = mState; lua_geti(L, LUA_REGISTRYINDEX, EVENT_TABLE); @@ -5406,7 +5435,14 @@ bool game_lua_kernel::run_wml_event(int ref, const vconfig& args, const game_eve if(lua_isnil(L, -1)) return false; luaW_pushvconfig(L, args); queued_event_context dummy(&ev, queued_events_); - return protected_call(1, 0); + if(protected_call(1, out ? 1 : 0)) { + if(out) { + *out = luaW_toboolean(L, -1); + lua_pop(L, 1); + } + return true; + } + return false; } diff --git a/src/scripting/game_lua_kernel.hpp b/src/scripting/game_lua_kernel.hpp index eb5381f3a58..36095ea6d65 100644 --- a/src/scripting/game_lua_kernel.hpp +++ b/src/scripting/game_lua_kernel.hpp @@ -251,9 +251,10 @@ public: * @param ref The unique index into the EVENT_TABLE within the Lua registry * @param args Arguments to pass to the event function, as a config * @param ev The event data for the event being fired + * @param out If non-null, receives the result of the called function (provided it is a boolean value) * @return Whether the function was successfully called; could be false if @a ref was invalid or if the function raised an error */ - bool run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev); + bool run_wml_event(int ref, const vconfig& args, const game_events::queued_event& ev, bool* out = nullptr); virtual void log_error(char const* msg, char const* context = "Lua error") override;