diff --git a/apps/openmw/mwlua/userdataserializer.cpp b/apps/openmw/mwlua/userdataserializer.cpp index b7ee0a2eda..6565ee0bde 100644 --- a/apps/openmw/mwlua/userdataserializer.cpp +++ b/apps/openmw/mwlua/userdataserializer.cpp @@ -1,6 +1,9 @@ #include "userdataserializer.hpp" +#include + #include +#include #include "object.hpp" @@ -26,9 +29,45 @@ namespace MWLua appendRefNum(out, data.as().id()); return true; } + if (data.is()) + { + appendObjectIdList(out, data.as().mIds); + return true; + } + if (data.is()) + { + appendObjectIdList(out, data.as().mIds); + return true; + } return false; } + constexpr static std::string_view sObjListTypeName = "objlist"; + void appendObjectIdList(LuaUtil::BinaryData& out, const ObjectIdList& objList) const + { + static_assert(sizeof(ESM::RefNum) == 8); + if constexpr (Misc::IS_LITTLE_ENDIAN) + append(out, sObjListTypeName, objList->data(), objList->size() * sizeof(ESM::RefNum)); + else + { + std::vector buf; + buf.reserve(objList->size()); + for (const ESM::RefNum& v : *objList) + buf.push_back({ Misc::toLittleEndian(v.mIndex), Misc::toLittleEndian(v.mContentFile) }); + append(out, sObjListTypeName, buf.data(), buf.size() * sizeof(ESM::RefNum)); + } + } + + void adjustRefNum(ESM::RefNum& refNum) const + { + if (refNum.hasContentFile() && mContentFileMapping) + { + auto iter = mContentFileMapping->find(refNum.mContentFile); + if (iter != mContentFileMapping->end()) + refNum.mContentFile = iter->second; + } + } + // 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. bool deserialize(std::string_view typeName, std::string_view binaryData, lua_State* lua) const override @@ -36,18 +75,32 @@ namespace MWLua if (typeName == sRefNumTypeName) { ObjectId id = loadRefNum(binaryData); - if (id.hasContentFile() && mContentFileMapping) - { - auto iter = mContentFileMapping->find(id.mContentFile); - if (iter != mContentFileMapping->end()) - id.mContentFile = iter->second; - } + adjustRefNum(id); if (mLocalSerializer) sol::stack::push(lua, LObject(id)); else sol::stack::push(lua, GObject(id)); return true; } + if (typeName == sObjListTypeName) + { + if (binaryData.size() % sizeof(ESM::RefNum) != 0) + throw std::runtime_error("Invalid size of ObjectIdList in MWLua::Serializer"); + ObjectIdList objList = std::make_shared>(); + objList->resize(binaryData.size() / sizeof(ESM::RefNum)); + std::memcpy(objList->data(), binaryData.data(), binaryData.size()); + for (ESM::RefNum& id : *objList) + { + id.mIndex = Misc::fromLittleEndian(id.mIndex); + id.mContentFile = Misc::fromLittleEndian(id.mContentFile); + adjustRefNum(id); + } + if (mLocalSerializer) + sol::stack::push(lua, LObjectList{ std::move(objList) }); + else + sol::stack::push(lua, GObjectList{ std::move(objList) }); + return true; + } return false; }