Don't expose LuaUtil::Callback to lua (!2733 for 0.48)

This commit is contained in:
Petr Mikheev 2023-02-14 09:40:22 +01:00
parent 628017a817
commit 1540c9679f
6 changed files with 50 additions and 28 deletions

View File

@ -109,9 +109,9 @@ namespace MWLua
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
return res; return res;
}; };
api["asyncCastRenderingRay"] = [context](const LuaUtil::Callback& callback, const osg::Vec3f& from, api["asyncCastRenderingRay"] = [context](
const osg::Vec3f& to) { const sol::table& callback, const osg::Vec3f& from, const osg::Vec3f& to) {
context.mLuaManager->addAction([context, callback, from, to] { context.mLuaManager->addAction([context, callback = LuaUtil::Callback::fromLua(callback), from, to] {
MWPhysics::RayCastingResult res; MWPhysics::RayCastingResult res;
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res)); context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res));

View File

@ -4,7 +4,7 @@
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <components/lua/scriptscontainer.hpp> #include <components/lua/asyncpackage.hpp>
#include <components/lua/storage.hpp> #include <components/lua/storage.hpp>
namespace namespace
@ -24,17 +24,16 @@ namespace
LuaUtil::LuaStorage storage(mLua); LuaUtil::LuaStorage storage(mLua);
std::vector<std::string> callbackCalls; std::vector<std::string> callbackCalls;
LuaUtil::Callback callback{ sol::table callbackHiddenData(mLua, sol::create);
sol::make_object(mLua, [&](const std::string& section, const sol::optional<std::string>& key) callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptsContainer::ScriptId{};
{ sol::table callback(mLua, sol::create);
if (key) callback[1] = [&](const std::string& section, const sol::optional<std::string>& key) {
callbackCalls.push_back(section + "_" + *key); if (key)
else callbackCalls.push_back(section + "_" + *key);
callbackCalls.push_back(section + "_*"); else
}), callbackCalls.push_back(section + "_*");
sol::table(mLua, sol::create)
}; };
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = "fakeId"; callback[2] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData };
mLua["mutable"] = storage.getMutableSection("test"); mLua["mutable"] = storage.getMutableSection("test");
mLua["ro"] = storage.getReadOnlySection("test"); mLua["ro"] = storage.getReadOnlySection("test");

View File

@ -22,6 +22,21 @@ namespace LuaUtil
std::string mName; std::string mName;
}; };
Callback Callback::fromLua(const sol::table& t)
{
return Callback{ t.raw_get<sol::main_protected_function>(1), t.raw_get<AsyncPackageId>(2).mHiddenData };
}
bool Callback::isLuaCallback(const sol::object& t)
{
if (!t.is<sol::table>())
return false;
sol::object meta = sol::table(t)[sol::metatable_key];
if (!meta.is<sol::table>())
return false;
return sol::table(meta).raw_get_or<bool, std::string_view, bool>("isCallback", false);
}
sol::function getAsyncPackageInitializer( sol::function getAsyncPackageInitializer(
lua_State* L, std::function<double()> simulationTimeFn, std::function<double()> gameTimeFn) lua_State* L, std::function<double()> simulationTimeFn, std::function<double()> gameTimeFn)
{ {
@ -53,13 +68,20 @@ namespace LuaUtil
asyncId.mContainer->setupUnsavableTimer( asyncId.mContainer->setupUnsavableTimer(
TimerType::GAME_TIME, gameTimeFn() + delay, asyncId.mScriptId, std::move(callback)); TimerType::GAME_TIME, gameTimeFn() + delay, asyncId.mScriptId, std::move(callback));
}; };
api["callback"] = [](const AsyncPackageId& asyncId, sol::main_protected_function fn) -> Callback {
return Callback{ std::move(fn), asyncId.mHiddenData };
};
sol::usertype<Callback> callbackType = lua.new_usertype<Callback>("Callback"); sol::table callbackMeta = sol::table::create(L);
callbackType[sol::meta_function::call] callbackMeta[sol::meta_function::call] = [](const sol::table& callback, sol::variadic_args va) {
= [](const Callback& callback, sol::variadic_args va) { return callback.call(sol::as_args(va)); }; return Callback::fromLua(callback).call(sol::as_args(va));
};
callbackMeta[sol::meta_function::to_string] = [] { return "Callback"; };
callbackMeta[sol::meta_function::metatable] = false;
callbackMeta["isCallback"] = true;
api["callback"] = [callbackMeta](const AsyncPackageId& asyncId, sol::main_protected_function fn) -> sol::table {
sol::table c = sol::table::create(fn.lua_state(), 2);
c.raw_set(1, std::move(fn), 2, asyncId);
c[sol::metatable_key] = callbackMeta;
return c;
};
auto initializer = [](sol::table hiddenData) { auto initializer = [](sol::table hiddenData) {
ScriptsContainer::ScriptId id = hiddenData[ScriptsContainer::sScriptIdKey]; ScriptsContainer::ScriptId id = hiddenData[ScriptsContainer::sScriptIdKey];

View File

@ -22,6 +22,9 @@ namespace LuaUtil
sol::main_protected_function mFunc; sol::main_protected_function mFunc;
sol::table mHiddenData; // same object as Script::mHiddenData in ScriptsContainer sol::table mHiddenData; // same object as Script::mHiddenData in ScriptsContainer
static bool isLuaCallback(const sol::object&);
static Callback fromLua(const sol::table&);
bool isValid() const { return mHiddenData[ScriptsContainer::sScriptIdKey] != sol::nil; } bool isValid() const { return mHiddenData[ScriptsContainer::sScriptIdKey] != sol::nil; }
template <typename... Args> template <typename... Args>

View File

@ -108,8 +108,7 @@ namespace LuaUtil
return section.mSection->get(key).getCopy(s); return section.mSection->get(key).getCopy(s);
}; };
sview["asTable"] = [](const SectionView& section) { return section.mSection->asTable(); }; sview["asTable"] = [](const SectionView& section) { return section.mSection->asTable(); };
sview["subscribe"] = [](const SectionView& section, const Callback& callback) sview["subscribe"] = [](const SectionView& section, const sol::table& callback) {
{
std::vector<Callback>& callbacks = section.mSection->mCallbacks; std::vector<Callback>& callbacks = section.mSection->mCallbacks;
if (!callbacks.empty() && callbacks.size() == callbacks.capacity()) if (!callbacks.empty() && callbacks.size() == callbacks.capacity())
{ {
@ -117,7 +116,7 @@ namespace LuaUtil
[&](const Callback& c) { return !c.isValid(); }), [&](const Callback& c) { return !c.isValid(); }),
callbacks.end()); callbacks.end());
} }
callbacks.push_back(callback); callbacks.push_back(Callback::fromLua(callback));
}; };
sview["reset"] = [](const SectionView& section, const sol::optional<sol::table>& newValues) sview["reset"] = [](const SectionView& section, const sol::optional<sol::table>& newValues)
{ {

View File

@ -104,13 +104,12 @@ namespace LuaUi
if (!eventsObj.is<sol::table>()) if (!eventsObj.is<sol::table>())
throw std::logic_error("The \"events\" layout field must be a table of callbacks"); throw std::logic_error("The \"events\" layout field must be a table of callbacks");
auto events = eventsObj.as<sol::table>(); auto events = eventsObj.as<sol::table>();
events.for_each([ext](const sol::object& name, const sol::object& callback) events.for_each([ext](const sol::object& name, const sol::object& callback) {
{ if (name.is<std::string>() && LuaUtil::Callback::isLuaCallback(callback))
if (name.is<std::string>() && callback.is<LuaUtil::Callback>()) ext->setCallback(name.as<std::string>(), LuaUtil::Callback::fromLua(callback));
ext->setCallback(name.as<std::string>(), callback.as<LuaUtil::Callback>());
else if (!name.is<std::string>()) else if (!name.is<std::string>())
Log(Debug::Warning) << "UI event key must be a string"; Log(Debug::Warning) << "UI event key must be a string";
else if (!callback.is<LuaUtil::Callback>()) else
Log(Debug::Warning) << "UI event handler for key \"" << name.as<std::string>() Log(Debug::Warning) << "UI event handler for key \"" << name.as<std::string>()
<< "\" must be an openmw.async.callback"; << "\" must be an openmw.async.callback";
}); });