1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-28 12:40:06 +00:00

Don't expose LuaUtil::Callback to lua

This commit is contained in:
Petr Mikheev 2023-02-14 09:40:22 +01:00
parent 71ba7b88e2
commit 65885d994f
6 changed files with 50 additions and 24 deletions

View File

@ -115,9 +115,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

@ -2,7 +2,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <components/lua/scriptscontainer.hpp> #include <components/lua/asyncpackage.hpp>
#include <components/lua/storage.hpp> #include <components/lua/storage.hpp>
namespace namespace
@ -24,15 +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::make_object(mLua, sol::table callbackHiddenData(mLua, sol::create);
[&](const std::string& section, const sol::optional<std::string>& key) { callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
if (key) sol::table callback(mLua, sol::create);
callbackCalls.push_back(section + "_" + *key); callback[1] = [&](const std::string& section, const sol::optional<std::string>& key) {
else if (key)
callbackCalls.push_back(section + "_*"); callbackCalls.push_back(section + "_" + *key);
}), else
sol::table(mLua, sol::create) }; callbackCalls.push_back(section + "_*");
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{}; };
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) {
ScriptId id = hiddenData[ScriptsContainer::sScriptIdKey]; 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

@ -111,7 +111,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())
{ {
@ -119,7 +119,7 @@ namespace LuaUtil
std::remove_if(callbacks.begin(), callbacks.end(), [&](const Callback& c) { return !c.isValid(); }), std::remove_if(callbacks.begin(), callbacks.end(), [&](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) {
if (section.mReadOnly) if (section.mReadOnly)

View File

@ -106,11 +106,11 @@ namespace LuaUi
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>() && callback.is<LuaUtil::Callback>()) if (name.is<std::string>() && LuaUtil::Callback::isLuaCallback(callback))
ext->setCallback(name.as<std::string>(), callback.as<LuaUtil::Callback>()); ext->setCallback(name.as<std::string>(), LuaUtil::Callback::fromLua(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";
}); });