Use the right deserializer for unloaded scripts

master
Evil Eye 2 months ago
parent 32a6ed6f49
commit 6572122acc

@ -161,6 +161,29 @@ return {
end end
} }
} }
)X");
constexpr VFS::Path::NormalizedView customDataPath("customdata.lua");
VFSTestFile customDataScript(R"X(
data = nil
return {
engineHandlers = {
onSave = function()
return data
end,
onLoad = function(state)
data = state
end,
onInit = function(state)
data = state
end
},
eventHandlers = {
WakeUp = function()
end
}
}
)X"); )X");
struct LuaScriptsContainerTest : Test struct LuaScriptsContainerTest : Test
@ -178,6 +201,7 @@ return {
{ overrideInterfacePath, &overrideInterfaceScript }, { overrideInterfacePath, &overrideInterfaceScript },
{ useInterfacePath, &useInterfaceScript }, { useInterfacePath, &useInterfaceScript },
{ unloadPath, &unloadScript }, { unloadPath, &unloadScript },
{ customDataPath, &customDataScript },
}); });
LuaUtil::ScriptsConfiguration mCfg; LuaUtil::ScriptsConfiguration mCfg;
@ -199,6 +223,7 @@ CUSTOM, PLAYER: testInterface.lua
CUSTOM, PLAYER: overrideInterface.lua CUSTOM, PLAYER: overrideInterface.lua
CUSTOM, PLAYER: useInterface.lua CUSTOM, PLAYER: useInterface.lua
CUSTOM: unload.lua CUSTOM: unload.lua
CUSTOM: customdata.lua
)X"); )X");
mCfg.init(std::move(cfg)); mCfg.init(std::move(cfg));
} }
@ -570,4 +595,58 @@ CUSTOM: unload.lua
scripts1.load(data); scripts1.load(data);
EXPECT_EQ(tracker.size(), 0); EXPECT_EQ(tracker.size(), 0);
} }
TEST_F(LuaScriptsContainerTest, LoadOrderChange)
{
LuaUtil::ScriptTracker tracker;
LuaUtil::ScriptsContainer scripts1(&mLua, "Test", &tracker, false);
LuaUtil::BasicSerializer serializer1;
LuaUtil::BasicSerializer serializer2([](int contentFileIndex) -> int {
if (contentFileIndex == 12)
return 34;
else if (contentFileIndex == 37)
return 12;
return contentFileIndex;
});
scripts1.setSerializer(&serializer1);
scripts1.setSavedDataDeserializer(&serializer2);
mLua.protectedCall([&](LuaUtil::LuaView& lua) {
sol::object id1 = sol::make_object_userdata(lua.sol(), ESM::RefNum{ 42, 12 });
sol::object id2 = sol::make_object_userdata(lua.sol(), ESM::RefNum{ 13, 37 });
sol::table table = lua.newTable();
table[id1] = id2;
LuaUtil::BinaryData serialized = LuaUtil::serialize(table, &serializer1);
EXPECT_TRUE(scripts1.addCustomScript(*mCfg.findId(customDataPath), serialized));
EXPECT_EQ(tracker.size(), 1);
for (int i = 0; i < 600; ++i)
tracker.unloadInactiveScripts(lua);
EXPECT_EQ(tracker.size(), 0);
scripts1.receiveEvent("WakeUp", {});
EXPECT_EQ(tracker.size(), 1);
});
ESM::LuaScripts data1;
ESM::LuaScripts data2;
scripts1.save(data1);
scripts1.load(data1);
scripts1.save(data2);
EXPECT_NE(data1.mScripts[0].mData, data2.mScripts[0].mData);
mLua.protectedCall([&](LuaUtil::LuaView& lua) {
sol::object deserialized = LuaUtil::deserialize(lua.sol(), data2.mScripts[0].mData, &serializer1);
EXPECT_TRUE(deserialized.is<sol::table>());
sol::table table = deserialized;
for (const auto& [key, value] : table)
{
EXPECT_TRUE(key.is<ESM::RefNum>());
EXPECT_TRUE(value.is<ESM::RefNum>());
EXPECT_EQ(key.as<ESM::RefNum>(), (ESM::RefNum{ 42, 34 }));
EXPECT_EQ(value.as<ESM::RefNum>(), (ESM::RefNum{ 13, 12 }));
return;
}
EXPECT_FALSE(true);
});
}
} }

@ -569,7 +569,6 @@ namespace MWLua
scripts->addPackage(name, package); scripts->addPackage(name, package);
} }
scripts->setSerializer(mLocalSerializer.get()); scripts->setSerializer(mLocalSerializer.get());
scripts->setSavedDataDeserializer(mLocalLoader.get());
MWWorld::RefData& refData = ptr.getRefData(); MWWorld::RefData& refData = ptr.getRefData();
refData.setLuaScripts(std::move(scripts)); refData.setLuaScripts(std::move(scripts));

@ -485,19 +485,34 @@ namespace LuaUtil
if (scriptInfo.mSavedData == nullptr) if (scriptInfo.mSavedData == nullptr)
continue; continue;
ESM::LuaScript& script = container.mScripts.emplace_back(*scriptInfo.mSavedData); ESM::LuaScript& script = container.mScripts.emplace_back(*scriptInfo.mSavedData);
for (ESM::LuaTimer& savedTimer : script.mTimers) if (!script.mData.empty())
{ {
try try
{ {
sol::object arg = deserialize(view.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer); sol::object state = deserialize(view.sol(), script.mData, mSavedDataDeserializer);
script.mData = serialize(state, mSerializer);
}
catch (std::exception& e)
{
printError(scriptId, "onLoad failed", e);
script.mData.clear();
}
}
for (auto it = script.mTimers.begin(); it != script.mTimers.end();)
{
try
{
sol::object arg = deserialize(view.sol(), it->mCallbackArgument, mSavedDataDeserializer);
// It is important if the order of content files was changed. The deserialize-serialize // It is important if the order of content files was changed. The deserialize-serialize
// procedure updates refnums, so timer.mSerializedArg may be not equal to // procedure updates refnums, so timer.mSerializedArg may be not equal to
// savedTimer.mCallbackArgument. // savedTimer.mCallbackArgument.
savedTimer.mCallbackArgument = serialize(arg, mSerializer); it->mCallbackArgument = serialize(arg, mSerializer);
++it;
} }
catch (std::exception& e) catch (std::exception& e)
{ {
printError(scriptId, "can not load timer", e); printError(scriptId, "can not load timer", e);
it = script.mTimers.erase(it);
} }
} }
} }
@ -547,8 +562,7 @@ namespace LuaUtil
{ {
try try
{ {
sol::object state sol::object state = deserialize(view.sol(), scriptInfo.mSavedData->mData, mSerializer);
= deserialize(view.sol(), scriptInfo.mSavedData->mData, mSavedDataDeserializer);
sol::object initializationData = deserialize(view.sol(), scriptInfo.mInitData, mSerializer); sol::object initializationData = deserialize(view.sol(), scriptInfo.mInitData, mSerializer);
LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData); LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData);
} }
@ -567,8 +581,8 @@ namespace LuaUtil
try try
{ {
timer.mArg = sol::main_object( timer.mArg
deserialize(view.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer)); = sol::main_object(deserialize(view.sol(), savedTimer.mCallbackArgument, mSerializer));
// It is important if the order of content files was changed. The deserialize-serialize // It is important if the order of content files was changed. The deserialize-serialize
// procedure updates refnums, so timer.mSerializedArg may be not equal to // procedure updates refnums, so timer.mSerializedArg may be not equal to
// savedTimer.mCallbackArgument. // savedTimer.mCallbackArgument.

Loading…
Cancel
Save