From 7e912d532f0f54e97c763fa4d62d4f385d2198cf Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 15 Sep 2024 22:54:26 -0400 Subject: [PATCH] Lua API: Add a valid key to the plugin context and info tables Previously the only way to tell they were valid would be a protected call on an existing member. --- src/scripting/application_lua_kernel.cpp | 30 +++++++++++++++++++++--- src/scripting/application_lua_kernel.hpp | 3 ++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/scripting/application_lua_kernel.cpp b/src/scripting/application_lua_kernel.cpp index 99463d20946..7bdba18c26a 100644 --- a/src/scripting/application_lua_kernel.cpp +++ b/src/scripting/application_lua_kernel.cpp @@ -110,7 +110,7 @@ application_lua_kernel::application_lua_kernel() cmd_log_ << lua_preferences::register_table(mState); } -application_lua_kernel::thread::thread(lua_State * T) : T_(T), started_(false) {} +application_lua_kernel::thread::thread(application_lua_kernel& owner, lua_State * T) : owner_(owner), T_(T), started_(false) {} std::string application_lua_kernel::thread::status() { @@ -194,7 +194,7 @@ application_lua_kernel::thread * application_lua_kernel::load_script_from_string throw game::lua_error(std::string("Error when executing a script to make a lua thread -- function was not produced, found a ") + lua_typename(T, lua_type(T, -1)) ); } - return new application_lua_kernel::thread(T); + return new application_lua_kernel::thread(*this, T); } application_lua_kernel::thread * application_lua_kernel::load_script_from_file(const std::string & file) @@ -211,7 +211,7 @@ application_lua_kernel::thread * application_lua_kernel::load_script_from_file(c throw game::lua_error(std::string("Error when executing a file to make a lua thread -- function was not produced, found a ") + lua_typename(T, lua_type(T, -1)) ); } - return new application_lua_kernel::thread(T); + return new application_lua_kernel::thread(*this, T); } struct lua_context_backend { @@ -273,6 +273,9 @@ application_lua_kernel::request_list application_lua_kernel::thread::run_script( // Now we have to create the context object. It is arranged as a table of boost functions. auto this_context_backend = std::make_shared(); lua_newtable(T_); // this will be the context table + lua_pushstring(T_, "valid"); + lua_pushboolean(T_, true); + lua_settable(T_, -3); for (const std::string & key : ctxt.callbacks_ | boost::adaptors::map_keys ) { lua_pushstring(T_, key.c_str()); lua_cpp::push_function(T_, std::bind(&impl_context_backend, std::placeholders::_1, this_context_backend, key)); @@ -284,6 +287,9 @@ application_lua_kernel::request_list application_lua_kernel::thread::run_script( lua_pushstring(T_, "name"); lua_pushstring(T_, ctxt.name_.c_str()); lua_settable(T_, -3); + lua_pushstring(T_, "valid"); + lua_pushboolean(T_, true); + lua_settable(T_, -3); for (const plugins_context::accessor_list::value_type & v : ctxt.accessors_) { const std::string & key = v.first; const plugins_context::accessor_function & func = v.second; @@ -292,7 +298,14 @@ application_lua_kernel::request_list application_lua_kernel::thread::run_script( lua_settable(T_, -3); } + // Push copies of the context and info tables so that we can mark them invalid for the next slice + lua_pushvalue(T_, -2); + lua_pushvalue(T_, -2); + // However, Lua can't handle having extra values on the stack when resuming a coroutine, + // so move the extra copy to the main thread instead. + lua_xmove(T_, owner_.get_state(), 2); // Now we resume the function, calling the coroutine with the three arguments (events, context, info). + // We ignore any values returned via arguments to yield() int numres = 0; lua_resume(T_, nullptr, 3, &numres); @@ -324,6 +337,17 @@ application_lua_kernel::request_list application_lua_kernel::thread::run_script( } } + // Pop any values that the resume left on the stack + lua_pop(T_, numres); + // Set "valid" to false on the now-expired context and info tables + lua_pushstring(owner_.get_state(), "valid"); + lua_pushboolean(owner_.get_state(), false); + lua_settable(owner_.get_state(), -3); + lua_pushstring(owner_.get_state(), "valid"); + lua_pushboolean(owner_.get_state(), false); + lua_settable(owner_.get_state(), -4); + lua_pop(owner_.get_state(), 2); + application_lua_kernel::request_list results; for (const plugins_manager::event & req : this_context_backend->requests) { diff --git a/src/scripting/application_lua_kernel.hpp b/src/scripting/application_lua_kernel.hpp index 33bdf9a6632..eb403b37b13 100644 --- a/src/scripting/application_lua_kernel.hpp +++ b/src/scripting/application_lua_kernel.hpp @@ -33,13 +33,14 @@ public: typedef std::vector> request_list; class thread { + application_lua_kernel& owner_; lua_State * T_; bool started_; thread(const thread&) = delete; thread& operator=(const thread&) = delete; - thread(lua_State *); + thread(application_lua_kernel&, lua_State *); public : bool is_running(); std::string status();