mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 21:39:41 +00:00
A few small fixes + expose makeReadOnly to Lua + an option to apply makeReadOnly during deserialize
This commit is contained in:
parent
e188f042d9
commit
7549496162
10 changed files with 61 additions and 27 deletions
|
@ -4,6 +4,14 @@
|
||||||
|
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
|
namespace sol
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct is_automagical<MWLua::LCell> : std::false_type {};
|
||||||
|
template <>
|
||||||
|
struct is_automagical<MWLua::GCell> : std::false_type {};
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
return input->isControllerButtonPressed(static_cast<SDL_GameControllerButton>(button));
|
return input->isControllerButtonPressed(static_cast<SDL_GameControllerButton>(button));
|
||||||
};
|
};
|
||||||
api["isMouseButtonPressed"] = [input](int button) -> bool
|
api["isMouseButtonPressed"] = [](int button) -> bool
|
||||||
{
|
{
|
||||||
return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button);
|
return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button);
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace MWLua
|
||||||
|
|
||||||
// Deserializes userdata of type "typeName" from binaryData. Should push the result on stack using sol::stack::push.
|
// Deserializes userdata of type "typeName" from binaryData. Should push the result on stack using sol::stack::push.
|
||||||
// Returns false if this type is not supported by this serializer.
|
// Returns false if this type is not supported by this serializer.
|
||||||
bool deserialize(std::string_view typeName, std::string_view binaryData, sol::state& lua) const override
|
bool deserialize(std::string_view typeName, std::string_view binaryData, lua_State* lua) const override
|
||||||
{
|
{
|
||||||
if (typeName == "o")
|
if (typeName == "o")
|
||||||
{
|
{
|
||||||
|
|
|
@ -121,14 +121,25 @@ namespace
|
||||||
std::string serialized = LuaUtil::serialize(table);
|
std::string serialized = LuaUtil::serialize(table);
|
||||||
EXPECT_EQ(serialized.size(), 123);
|
EXPECT_EQ(serialized.size(), 123);
|
||||||
sol::table res_table = LuaUtil::deserialize(lua, serialized);
|
sol::table res_table = LuaUtil::deserialize(lua, serialized);
|
||||||
|
sol::table res_readonly_table = LuaUtil::deserialize(lua, serialized, nullptr, true);
|
||||||
|
|
||||||
EXPECT_EQ(res_table.get<int>("aa"), 1);
|
for (auto t : {res_table, res_readonly_table})
|
||||||
EXPECT_EQ(res_table.get<bool>("ab"), true);
|
{
|
||||||
EXPECT_EQ(res_table.get<sol::table>("nested").get<int>("aa"), 2);
|
EXPECT_EQ(t.get<int>("aa"), 1);
|
||||||
EXPECT_EQ(res_table.get<sol::table>("nested").get<std::string>("bb"), "something");
|
EXPECT_EQ(t.get<bool>("ab"), true);
|
||||||
EXPECT_FLOAT_EQ(res_table.get<sol::table>("nested").get<double>(5), -0.5);
|
EXPECT_EQ(t.get<sol::table>("nested").get<int>("aa"), 2);
|
||||||
EXPECT_EQ(res_table.get<osg::Vec2f>(1), osg::Vec2f(1, 2));
|
EXPECT_EQ(t.get<sol::table>("nested").get<std::string>("bb"), "something");
|
||||||
EXPECT_EQ(res_table.get<osg::Vec2f>(2), osg::Vec2f(2, 1));
|
EXPECT_FLOAT_EQ(t.get<sol::table>("nested").get<double>(5), -0.5);
|
||||||
|
EXPECT_EQ(t.get<osg::Vec2f>(1), osg::Vec2f(1, 2));
|
||||||
|
EXPECT_EQ(t.get<osg::Vec2f>(2), osg::Vec2f(2, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
lua["t"] = res_table;
|
||||||
|
lua["ro_t"] = res_readonly_table;
|
||||||
|
EXPECT_NO_THROW(lua.safe_script("t.x = 5"));
|
||||||
|
EXPECT_NO_THROW(lua.safe_script("t.nested.x = 5"));
|
||||||
|
EXPECT_ERROR(lua.safe_script("ro_t.x = 5"), "userdata value");
|
||||||
|
EXPECT_ERROR(lua.safe_script("ro_t.nested.x = 5"), "userdata value");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestStruct1 { double a, b; };
|
struct TestStruct1 { double a, b; };
|
||||||
|
@ -157,7 +168,7 @@ namespace
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deserialize(std::string_view typeName, std::string_view binaryData, sol::state& lua) const override
|
bool deserialize(std::string_view typeName, std::string_view binaryData, lua_State* lua) const override
|
||||||
{
|
{
|
||||||
if (typeName == "ts1")
|
if (typeName == "ts1")
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,6 +120,9 @@ namespace
|
||||||
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(0.1, 0, 1.5)"), 0.1);
|
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(0.1, 0, 1.5)"), 0.1);
|
||||||
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(-0.1, 0, 1.5)"), 0);
|
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(-0.1, 0, 1.5)"), 0);
|
||||||
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(2.1, 0, 1.5)"), 1.5);
|
EXPECT_FLOAT_EQ(get<float>(lua, "util.clamp(2.1, 0, 1.5)"), 1.5);
|
||||||
|
lua.safe_script("t = util.makeReadOnly({x = 1})");
|
||||||
|
EXPECT_FLOAT_EQ(get<float>(lua, "t.x"), 1);
|
||||||
|
EXPECT_ERROR(lua.safe_script("t.y = 2"), "userdata value");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,8 @@ namespace LuaUtil
|
||||||
|
|
||||||
lua_State* lua = table.lua_state();
|
lua_State* lua = table.lua_state();
|
||||||
table[sol::meta_function::index] = table;
|
table[sol::meta_function::index] = table;
|
||||||
sol::stack::push(lua, std::move(table));
|
|
||||||
lua_newuserdata(lua, 0);
|
lua_newuserdata(lua, 0);
|
||||||
lua_pushvalue(lua, -2);
|
sol::stack::push(lua, std::move(table));
|
||||||
lua_setmetatable(lua, -2);
|
lua_setmetatable(lua, -2);
|
||||||
return sol::stack::pop<sol::table>(lua);
|
return sol::stack::pop<sol::table>(lua);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <components/misc/endianness.hpp>
|
#include <components/misc/endianness.hpp>
|
||||||
|
|
||||||
|
#include "luastate.hpp"
|
||||||
|
|
||||||
namespace LuaUtil
|
namespace LuaUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -147,7 +149,8 @@ namespace LuaUtil
|
||||||
throw std::runtime_error("Unknown Lua type.");
|
throw std::runtime_error("Unknown Lua type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deserializeImpl(sol::state& lua, std::string_view& binaryData, const UserdataSerializer* customSerializer)
|
static void deserializeImpl(lua_State* lua, std::string_view& binaryData,
|
||||||
|
const UserdataSerializer* customSerializer, bool readOnly)
|
||||||
{
|
{
|
||||||
if (binaryData.empty())
|
if (binaryData.empty())
|
||||||
throw std::runtime_error("Unexpected end of serialized data.");
|
throw std::runtime_error("Unexpected end of serialized data.");
|
||||||
|
@ -176,22 +179,22 @@ namespace LuaUtil
|
||||||
if (type & SHORT_STRING_FLAG)
|
if (type & SHORT_STRING_FLAG)
|
||||||
{
|
{
|
||||||
size_t size = type & 0x1f;
|
size_t size = type & 0x1f;
|
||||||
sol::stack::push<std::string_view>(lua.lua_state(), binaryData.substr(0, size));
|
sol::stack::push<std::string_view>(lua, binaryData.substr(0, size));
|
||||||
binaryData = binaryData.substr(size);
|
binaryData = binaryData.substr(size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (static_cast<SerializedType>(type))
|
switch (static_cast<SerializedType>(type))
|
||||||
{
|
{
|
||||||
case SerializedType::NUMBER:
|
case SerializedType::NUMBER:
|
||||||
sol::stack::push<double>(lua.lua_state(), getValue<double>(binaryData));
|
sol::stack::push<double>(lua, getValue<double>(binaryData));
|
||||||
return;
|
return;
|
||||||
case SerializedType::BOOLEAN:
|
case SerializedType::BOOLEAN:
|
||||||
sol::stack::push<bool>(lua.lua_state(), getValue<char>(binaryData) != 0);
|
sol::stack::push<bool>(lua, getValue<char>(binaryData) != 0);
|
||||||
return;
|
return;
|
||||||
case SerializedType::LONG_STRING:
|
case SerializedType::LONG_STRING:
|
||||||
{
|
{
|
||||||
uint32_t size = getValue<uint32_t>(binaryData);
|
uint32_t size = getValue<uint32_t>(binaryData);
|
||||||
sol::stack::push<std::string_view>(lua.lua_state(), binaryData.substr(0, size));
|
sol::stack::push<std::string_view>(lua, binaryData.substr(0, size));
|
||||||
binaryData = binaryData.substr(size);
|
binaryData = binaryData.substr(size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -200,13 +203,15 @@ namespace LuaUtil
|
||||||
lua_createtable(lua, 0, 0);
|
lua_createtable(lua, 0, 0);
|
||||||
while (!binaryData.empty() && binaryData[0] != char(SerializedType::TABLE_END))
|
while (!binaryData.empty() && binaryData[0] != char(SerializedType::TABLE_END))
|
||||||
{
|
{
|
||||||
deserializeImpl(lua, binaryData, customSerializer);
|
deserializeImpl(lua, binaryData, customSerializer, readOnly);
|
||||||
deserializeImpl(lua, binaryData, customSerializer);
|
deserializeImpl(lua, binaryData, customSerializer, readOnly);
|
||||||
lua_settable(lua, -3);
|
lua_settable(lua, -3);
|
||||||
}
|
}
|
||||||
if (binaryData.empty())
|
if (binaryData.empty())
|
||||||
throw std::runtime_error("Unexpected end of serialized data.");
|
throw std::runtime_error("Unexpected end of serialized data.");
|
||||||
binaryData = binaryData.substr(1);
|
binaryData = binaryData.substr(1);
|
||||||
|
if (readOnly)
|
||||||
|
sol::stack::push(lua, makeReadOnly(sol::stack::pop<sol::table>(lua)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SerializedType::TABLE_END:
|
case SerializedType::TABLE_END:
|
||||||
|
@ -215,7 +220,7 @@ namespace LuaUtil
|
||||||
{
|
{
|
||||||
float x = getValue<float>(binaryData);
|
float x = getValue<float>(binaryData);
|
||||||
float y = getValue<float>(binaryData);
|
float y = getValue<float>(binaryData);
|
||||||
sol::stack::push<osg::Vec2f>(lua.lua_state(), osg::Vec2f(x, y));
|
sol::stack::push<osg::Vec2f>(lua, osg::Vec2f(x, y));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SerializedType::VEC3:
|
case SerializedType::VEC3:
|
||||||
|
@ -223,7 +228,7 @@ namespace LuaUtil
|
||||||
float x = getValue<float>(binaryData);
|
float x = getValue<float>(binaryData);
|
||||||
float y = getValue<float>(binaryData);
|
float y = getValue<float>(binaryData);
|
||||||
float z = getValue<float>(binaryData);
|
float z = getValue<float>(binaryData);
|
||||||
sol::stack::push<osg::Vec3f>(lua.lua_state(), osg::Vec3f(x, y, z));
|
sol::stack::push<osg::Vec3f>(lua, osg::Vec3f(x, y, z));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +245,8 @@ namespace LuaUtil
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object deserialize(sol::state& lua, std::string_view binaryData, const UserdataSerializer* customSerializer)
|
sol::object deserialize(lua_State* lua, std::string_view binaryData,
|
||||||
|
const UserdataSerializer* customSerializer, bool readOnly)
|
||||||
{
|
{
|
||||||
if (binaryData.empty())
|
if (binaryData.empty())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
|
@ -248,10 +254,10 @@ namespace LuaUtil
|
||||||
throw std::runtime_error("Incorrect version of Lua serialization format: " +
|
throw std::runtime_error("Incorrect version of Lua serialization format: " +
|
||||||
std::to_string(static_cast<unsigned>(binaryData[0])));
|
std::to_string(static_cast<unsigned>(binaryData[0])));
|
||||||
binaryData = binaryData.substr(1);
|
binaryData = binaryData.substr(1);
|
||||||
deserializeImpl(lua, binaryData, customSerializer);
|
deserializeImpl(lua, binaryData, customSerializer, readOnly);
|
||||||
if (!binaryData.empty())
|
if (!binaryData.empty())
|
||||||
throw std::runtime_error("Unexpected data after serialized object");
|
throw std::runtime_error("Unexpected data after serialized object");
|
||||||
return sol::stack::pop<sol::object>(lua.lua_state());
|
return sol::stack::pop<sol::object>(lua);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef COMPONENTS_LUA_SERIALIZATION_H
|
#ifndef COMPONENTS_LUA_SERIALIZATION_H
|
||||||
#define COMPONENTS_LUA_SERIALIZATION_H
|
#define COMPONENTS_LUA_SERIALIZATION_H
|
||||||
|
|
||||||
#include <limits> // missing from sol/sol.hpp
|
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
namespace LuaUtil
|
namespace LuaUtil
|
||||||
|
@ -21,14 +20,15 @@ namespace LuaUtil
|
||||||
|
|
||||||
// Deserializes userdata of type "typeName" from binaryData. Should push the result on stack using sol::stack::push.
|
// Deserializes userdata of type "typeName" from binaryData. Should push the result on stack using sol::stack::push.
|
||||||
// Returns false if this type is not supported by this serializer.
|
// Returns false if this type is not supported by this serializer.
|
||||||
virtual bool deserialize(std::string_view typeName, std::string_view binaryData, sol::state&) const = 0;
|
virtual bool deserialize(std::string_view typeName, std::string_view binaryData, lua_State*) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void append(BinaryData&, std::string_view typeName, const void* data, size_t dataSize);
|
static void append(BinaryData&, std::string_view typeName, const void* data, size_t dataSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
BinaryData serialize(const sol::object&, const UserdataSerializer* customSerializer = nullptr);
|
BinaryData serialize(const sol::object&, const UserdataSerializer* customSerializer = nullptr);
|
||||||
sol::object deserialize(sol::state& lua, std::string_view binaryData, const UserdataSerializer* customSerializer = nullptr);
|
sol::object deserialize(lua_State* lua, std::string_view binaryData,
|
||||||
|
const UserdataSerializer* customSerializer = nullptr, bool readOnly = false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,6 +175,7 @@ namespace LuaUtil
|
||||||
util["clamp"] = [](float value, float from, float to) { return std::clamp(value, from, to); };
|
util["clamp"] = [](float value, float from, float to) { return std::clamp(value, from, to); };
|
||||||
// NOTE: `util["clamp"] = std::clamp<float>` causes error 'AddressSanitizer: stack-use-after-scope'
|
// NOTE: `util["clamp"] = std::clamp<float>` causes error 'AddressSanitizer: stack-use-after-scope'
|
||||||
util["normalizeAngle"] = &Misc::normalizeAngle;
|
util["normalizeAngle"] = &Misc::normalizeAngle;
|
||||||
|
util["makeReadOnly"] = &makeReadOnly;
|
||||||
|
|
||||||
return util;
|
return util;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,12 @@
|
||||||
-- @param #number angle Angle in radians
|
-- @param #number angle Angle in radians
|
||||||
-- @return #number Angle in range `[-pi, pi]`
|
-- @return #number Angle in range `[-pi, pi]`
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Makes a table read only.
|
||||||
|
-- @function [parent=#util] makeReadOnly
|
||||||
|
-- @param #table table Any table.
|
||||||
|
-- @return #table The same table wrapped with read only userdata.
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Immutable 2D vector
|
-- Immutable 2D vector
|
||||||
|
|
Loading…
Reference in a new issue