Don't expose LuaUtil::Callback to lua

pull/3229/head
Petr Mikheev 2 years ago
parent 71ba7b88e2
commit 65885d994f

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

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

@ -22,6 +22,21 @@ namespace LuaUtil
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(
lua_State* L, std::function<double()> simulationTimeFn, std::function<double()> gameTimeFn)
{
@ -53,13 +68,20 @@ namespace LuaUtil
asyncId.mContainer->setupUnsavableTimer(
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");
callbackType[sol::meta_function::call]
= [](const Callback& callback, sol::variadic_args va) { return callback.call(sol::as_args(va)); };
sol::table callbackMeta = sol::table::create(L);
callbackMeta[sol::meta_function::call] = [](const sol::table& callback, sol::variadic_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) {
ScriptId id = hiddenData[ScriptsContainer::sScriptIdKey];

@ -22,6 +22,9 @@ namespace LuaUtil
sol::main_protected_function mFunc;
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; }
template <typename... Args>

@ -111,7 +111,7 @@ namespace LuaUtil
return section.mSection->get(key).getCopy(s);
};
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;
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(); }),
callbacks.end());
}
callbacks.push_back(callback);
callbacks.push_back(Callback::fromLua(callback));
};
sview["reset"] = [](const SectionView& section, const sol::optional<sol::table>& newValues) {
if (section.mReadOnly)

@ -106,11 +106,11 @@ namespace LuaUi
throw std::logic_error("The \"events\" layout field must be a table of callbacks");
auto events = eventsObj.as<sol::table>();
events.for_each([ext](const sol::object& name, const sol::object& callback) {
if (name.is<std::string>() && callback.is<LuaUtil::Callback>())
ext->setCallback(name.as<std::string>(), callback.as<LuaUtil::Callback>());
if (name.is<std::string>() && LuaUtil::Callback::isLuaCallback(callback))
ext->setCallback(name.as<std::string>(), LuaUtil::Callback::fromLua(callback));
else if (!name.is<std::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>()
<< "\" must be an openmw.async.callback";
});

Loading…
Cancel
Save