mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Merge branch 'pcallallthethings' into 'master'
Wrap all memory allocating Lua functions in protected calls Closes #8099 See merge request OpenMW/openmw!4336
This commit is contained in:
commit
b3677d07fd
@ -13,12 +13,14 @@ namespace
|
||||
{
|
||||
void SetUp() override
|
||||
{
|
||||
mLua.sol()["callback"] = [&](sol::protected_function fn) -> LuaUtil::Callback {
|
||||
sol::table hiddenData(mLua.sol(), sol::create);
|
||||
hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
|
||||
return LuaUtil::Callback{ std::move(fn), hiddenData };
|
||||
};
|
||||
mLua.sol()["pass"] = [this](LuaUtil::Callback callback) { mCb = callback; };
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
view.sol()["callback"] = [](sol::this_state state, sol::protected_function fn) -> LuaUtil::Callback {
|
||||
sol::table hiddenData(state, sol::create);
|
||||
hiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
|
||||
return LuaUtil::Callback{ std::move(fn), hiddenData };
|
||||
};
|
||||
view.sol()["pass"] = [&](LuaUtil::Callback callback) { mCb = callback; };
|
||||
});
|
||||
}
|
||||
|
||||
LuaUtil::LuaState mLua{ nullptr, nullptr };
|
||||
@ -28,25 +30,29 @@ namespace
|
||||
TEST_F(LuaCoroutineCallbackTest, CoroutineCallbacks)
|
||||
{
|
||||
internal::CaptureStdout();
|
||||
mLua.sol().safe_script(R"X(
|
||||
local s = 'test'
|
||||
coroutine.wrap(function()
|
||||
pass(callback(function(v) print(s) end))
|
||||
end)()
|
||||
)X");
|
||||
mLua.sol().collect_garbage();
|
||||
mCb.call();
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
view.sol().safe_script(R"X(
|
||||
local s = 'test'
|
||||
coroutine.wrap(function()
|
||||
pass(callback(function(v) print(s) end))
|
||||
end)()
|
||||
)X");
|
||||
view.sol().collect_garbage();
|
||||
mCb.call();
|
||||
});
|
||||
EXPECT_THAT(internal::GetCapturedStdout(), "test\n");
|
||||
}
|
||||
|
||||
TEST_F(LuaCoroutineCallbackTest, ErrorInCoroutineCallbacks)
|
||||
{
|
||||
mLua.sol().safe_script(R"X(
|
||||
coroutine.wrap(function()
|
||||
pass(callback(function() error('COROUTINE CALLBACK') end))
|
||||
end)()
|
||||
)X");
|
||||
mLua.sol().collect_garbage();
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
view.sol().safe_script(R"X(
|
||||
coroutine.wrap(function()
|
||||
pass(callback(function() error('COROUTINE CALLBACK') end))
|
||||
end)()
|
||||
)X");
|
||||
view.sol().collect_garbage();
|
||||
});
|
||||
EXPECT_ERROR(mCb.call(), "COROUTINE CALLBACK");
|
||||
}
|
||||
}
|
||||
|
@ -81,84 +81,87 @@ you_have_arrows: "Arrows count: {count}"
|
||||
TEST_F(LuaL10nTest, L10n)
|
||||
{
|
||||
LuaUtil::LuaState lua{ mVFS.get(), &mCfg };
|
||||
sol::state_view& l = lua.sol();
|
||||
internal::CaptureStdout();
|
||||
l10n::Manager l10nManager(mVFS.get());
|
||||
l10nManager.setPreferredLocales({ "de", "en" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n");
|
||||
lua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
sol::state_view& l = view.sol();
|
||||
internal::CaptureStdout();
|
||||
l10n::Manager l10nManager(mVFS.get());
|
||||
l10nManager.setPreferredLocales({ "de", "en" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n");
|
||||
|
||||
l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager);
|
||||
l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager);
|
||||
|
||||
internal::CaptureStdout();
|
||||
l.safe_script("t1 = l10n('Test1')");
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n");
|
||||
internal::CaptureStdout();
|
||||
l.safe_script("t1 = l10n('Test1')");
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n");
|
||||
|
||||
internal::CaptureStdout();
|
||||
l.safe_script("t2 = l10n('Test2')");
|
||||
{
|
||||
std::string output = internal::GetCapturedStdout();
|
||||
EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled"));
|
||||
}
|
||||
internal::CaptureStdout();
|
||||
l.safe_script("t2 = l10n('Test2')");
|
||||
{
|
||||
std::string output = internal::GetCapturedStdout();
|
||||
EXPECT_THAT(output, HasSubstr("Language file \"l10n/Test2/en.yaml\" is enabled"));
|
||||
}
|
||||
|
||||
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Guten Morgen.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Guten Morgen.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "Du hast ein Pfeil.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "Du hast 5 Pfeile.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
|
||||
internal::CaptureStdout();
|
||||
l10nManager.setPreferredLocales({ "en", "de" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Preferred locales: gmst en de\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
|
||||
internal::CaptureStdout();
|
||||
l10nManager.setPreferredLocales({ "en", "de" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Preferred locales: gmst en de\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
|
||||
|
||||
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Good morning.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "You have one arrow.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=1})"), "You came in 1st place.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=100})"), "You came in 100th place.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=1})"), "There is one thing.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=100})"), "There are one hundred things.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('duration', {num=100})"), "It took 1:40");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('numbers', {int=123, double=123.456})"),
|
||||
"123 and 123 are integers, but 123.456 is a double");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('rounding', {value=123.456789})"), "123.46");
|
||||
// Check that failed messages display the key instead of an empty string
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{mismatched_braces')"), "{mismatched_braces");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{unknown_arg}')"), "{unknown_arg}");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{num, integer}', {num=1})"), "{num, integer}");
|
||||
// Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency.
|
||||
l10nManager.setPreferredLocales({ "en-US", "de" });
|
||||
EXPECT_EQ(get<std::string>(l, "t1('currency', {money=10000.10})"), "You have $10,000.10");
|
||||
// Note: Not defined in English localisation file, so we fall back to the German before falling back to the key
|
||||
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('good_morning')"), "Good morning.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=1})"), "You have one arrow.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('you_have_arrows', {count=5})"), "You have 5 arrows.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"male\"})"), "He is coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"female\"})"), "She is coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"blah\"})"), "They are coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('pc_must_come', {PCGender=\"other\"})"), "They are coming with us.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=0.1})"), "The quest is 10% complete.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('quest_completion', {done=1})"), "The quest is 100% complete.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=1})"), "You came in 1st place.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('ordinal', {num=100})"), "You came in 100th place.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=1})"), "There is one thing.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('spellout', {num=100})"), "There are one hundred things.");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('duration', {num=100})"), "It took 1:40");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('numbers', {int=123, double=123.456})"),
|
||||
"123 and 123 are integers, but 123.456 is a double");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('rounding', {value=123.456789})"), "123.46");
|
||||
// Check that failed messages display the key instead of an empty string
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{mismatched_braces')"), "{mismatched_braces");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{unknown_arg}')"), "{unknown_arg}");
|
||||
EXPECT_EQ(get<std::string>(l, "t1('{num, integer}', {num=1})"), "{num, integer}");
|
||||
// Doesn't give a valid currency symbol with `en`. Not that openmw is designed for real world currency.
|
||||
l10nManager.setPreferredLocales({ "en-US", "de" });
|
||||
EXPECT_EQ(get<std::string>(l, "t1('currency', {money=10000.10})"), "You have $10,000.10");
|
||||
// Note: Not defined in English localisation file, so we fall back to the German before falling back to the
|
||||
// key
|
||||
EXPECT_EQ(get<std::string>(l, "t1('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('good_morning')"), "Morning!");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
|
||||
// Test that locales with variants and country codes fall back to more generic locales
|
||||
internal::CaptureStdout();
|
||||
l10nManager.setPreferredLocales({ "en-GB-oed", "de" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Preferred locales: gmst en_GB_OED de\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
// Test that locales with variants and country codes fall back to more generic locales
|
||||
internal::CaptureStdout();
|
||||
l10nManager.setPreferredLocales({ "en-GB-oed", "de" });
|
||||
EXPECT_THAT(internal::GetCapturedStdout(),
|
||||
"Preferred locales: gmst en_GB_OED de\n"
|
||||
"Language file \"l10n/Test1/en.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test1/de.yaml\" is enabled\n"
|
||||
"Language file \"l10n/Test2/en.yaml\" is enabled\n");
|
||||
EXPECT_EQ(get<std::string>(l, "t2('you_have_arrows', {count=3})"), "Arrows count: 3");
|
||||
|
||||
// Test setting fallback language
|
||||
l.safe_script("t3 = l10n('Test3', 'de')");
|
||||
l10nManager.setPreferredLocales({ "en" });
|
||||
EXPECT_EQ(get<std::string>(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
// Test setting fallback language
|
||||
l.safe_script("t3 = l10n('Test3', 'de')");
|
||||
l10nManager.setPreferredLocales({ "en" });
|
||||
EXPECT_EQ(get<std::string>(l, "t3('Hello {name}!', {name='World'})"), "Hallo World!");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -97,26 +97,26 @@ return {
|
||||
|
||||
TEST_F(LuaStateTest, ToString)
|
||||
{
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), 3.14)), "3.14");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), true)), "true");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), 3.14)), "3.14");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), true)), "true");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::nil), "nil");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), "something")), "\"something\"");
|
||||
EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.unsafeState(), "something")), "\"something\"");
|
||||
}
|
||||
|
||||
TEST_F(LuaStateTest, Cast)
|
||||
{
|
||||
EXPECT_EQ(LuaUtil::cast<int>(sol::make_object(mLua.sol(), 3.14)), 3);
|
||||
EXPECT_ERROR(
|
||||
LuaUtil::cast<int>(sol::make_object(mLua.sol(), "3.14")), "Value \"\"3.14\"\" can not be casted to int");
|
||||
EXPECT_ERROR(LuaUtil::cast<std::string_view>(sol::make_object(mLua.sol(), sol::nil)),
|
||||
EXPECT_EQ(LuaUtil::cast<int>(sol::make_object(mLua.unsafeState(), 3.14)), 3);
|
||||
EXPECT_ERROR(LuaUtil::cast<int>(sol::make_object(mLua.unsafeState(), "3.14")),
|
||||
"Value \"\"3.14\"\" can not be casted to int");
|
||||
EXPECT_ERROR(LuaUtil::cast<std::string_view>(sol::make_object(mLua.unsafeState(), sol::nil)),
|
||||
"Value \"nil\" can not be casted to string");
|
||||
EXPECT_ERROR(LuaUtil::cast<std::string>(sol::make_object(mLua.sol(), sol::nil)),
|
||||
EXPECT_ERROR(LuaUtil::cast<std::string>(sol::make_object(mLua.unsafeState(), sol::nil)),
|
||||
"Value \"nil\" can not be casted to string");
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::table>(sol::make_object(mLua.sol(), sol::nil)),
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::table>(sol::make_object(mLua.unsafeState(), sol::nil)),
|
||||
"Value \"nil\" can not be casted to sol::table");
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::function>(sol::make_object(mLua.sol(), "3.14")),
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::function>(sol::make_object(mLua.unsafeState(), "3.14")),
|
||||
"Value \"\"3.14\"\" can not be casted to sol::function");
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::protected_function>(sol::make_object(mLua.sol(), "3.14")),
|
||||
EXPECT_ERROR(LuaUtil::cast<sol::protected_function>(sol::make_object(mLua.unsafeState(), "3.14")),
|
||||
"Value \"\"3.14\"\" can not be casted to sol::function");
|
||||
}
|
||||
|
||||
@ -186,21 +186,22 @@ return {
|
||||
TEST_F(LuaStateTest, ProvideAPI)
|
||||
{
|
||||
LuaUtil::LuaState lua(mVFS.get(), &mCfg);
|
||||
lua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
sol::table api1 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api1"));
|
||||
sol::table api2 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api2"));
|
||||
|
||||
sol::table api1 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api1"));
|
||||
sol::table api2 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api2"));
|
||||
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } });
|
||||
|
||||
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } });
|
||||
lua.addCommonPackage("sqrlib", view.sol().create_table_with("sqr", [](int x) { return x * x; }));
|
||||
|
||||
lua.addCommonPackage("sqrlib", lua.sol().create_table_with("sqr", [](int x) { return x * x; }));
|
||||
sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } });
|
||||
|
||||
sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } });
|
||||
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
|
||||
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
|
||||
|
||||
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
|
||||
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
|
||||
|
||||
EXPECT_EQ(LuaUtil::call(script1["apiName"]).get<std::string>(), "api1");
|
||||
EXPECT_EQ(LuaUtil::call(script2["apiName"]).get<std::string>(), "api2");
|
||||
EXPECT_EQ(LuaUtil::call(script1["apiName"]).get<std::string>(), "api1");
|
||||
EXPECT_EQ(LuaUtil::call(script2["apiName"]).get<std::string>(), "api2");
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LuaStateTest, GetLuaVersion)
|
||||
@ -212,7 +213,7 @@ return {
|
||||
{
|
||||
auto getMem = [&] {
|
||||
for (int i = 0; i < 5; ++i)
|
||||
lua_gc(mLua.sol(), LUA_GCCOLLECT, 0);
|
||||
lua_gc(mLua.unsafeState(), LUA_GCCOLLECT, 0);
|
||||
return mLua.getTotalMemoryUsage();
|
||||
};
|
||||
int64_t memWithScript;
|
||||
|
@ -198,8 +198,9 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua")));
|
||||
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua")));
|
||||
|
||||
std::string X0 = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5));
|
||||
std::string X1 = LuaUtil::serialize(mLua.sol().create_table_with("x", 1.5));
|
||||
sol::state_view sol = mLua.unsafeState();
|
||||
std::string X0 = LuaUtil::serialize(sol.create_table_with("x", 0.5));
|
||||
std::string X1 = LuaUtil::serialize(sol.create_table_with("x", 1.5));
|
||||
|
||||
{
|
||||
testing::internal::CaptureStdout();
|
||||
@ -243,7 +244,8 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test1.lua")));
|
||||
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("stopEvent.lua")));
|
||||
EXPECT_TRUE(scripts.addCustomScript(*mCfg.findId("test2.lua")));
|
||||
std::string X = LuaUtil::serialize(mLua.sol().create_table_with("x", 0.5));
|
||||
sol::state_view sol = mLua.unsafeState();
|
||||
std::string X = LuaUtil::serialize(sol.create_table_with("x", 0.5));
|
||||
|
||||
{
|
||||
testing::internal::CaptureStdout();
|
||||
@ -334,8 +336,9 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
scripts1.addAutoStartedScripts();
|
||||
EXPECT_TRUE(scripts1.addCustomScript(*mCfg.findId("test1.lua")));
|
||||
|
||||
scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 1, "x", 0.5, "y", 3.5)));
|
||||
scripts1.receiveEvent("Set", LuaUtil::serialize(mLua.sol().create_table_with("n", 2, "x", 2.5, "y", 1.5)));
|
||||
sol::state_view sol = mLua.unsafeState();
|
||||
scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 1, "x", 0.5, "y", 3.5)));
|
||||
scripts1.receiveEvent("Set", LuaUtil::serialize(sol.create_table_with("n", 2, "x", 2.5, "y", 1.5)));
|
||||
|
||||
ESM::LuaScripts data;
|
||||
scripts1.save(data);
|
||||
@ -379,10 +382,10 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
EXPECT_EQ(internal::GetCapturedStdout(), "");
|
||||
|
||||
int counter1 = 0, counter2 = 0, counter3 = 0, counter4 = 0;
|
||||
sol::function fn1 = sol::make_object(mLua.sol(), [&]() { counter1++; });
|
||||
sol::function fn2 = sol::make_object(mLua.sol(), [&]() { counter2++; });
|
||||
sol::function fn3 = sol::make_object(mLua.sol(), [&](int d) { counter3 += d; });
|
||||
sol::function fn4 = sol::make_object(mLua.sol(), [&](int d) { counter4 += d; });
|
||||
sol::function fn1 = sol::make_object(mLua.unsafeState(), [&]() { counter1++; });
|
||||
sol::function fn2 = sol::make_object(mLua.unsafeState(), [&]() { counter2++; });
|
||||
sol::function fn3 = sol::make_object(mLua.unsafeState(), [&](int d) { counter3 += d; });
|
||||
sol::function fn4 = sol::make_object(mLua.unsafeState(), [&](int d) { counter4 += d; });
|
||||
|
||||
scripts.registerTimerCallback(test1Id, "A", fn3);
|
||||
scripts.registerTimerCallback(test1Id, "B", fn4);
|
||||
@ -391,12 +394,16 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
|
||||
scripts.processTimers(1, 2);
|
||||
|
||||
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.sol(), 3));
|
||||
scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.sol(), 4));
|
||||
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.sol(), 1));
|
||||
scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.sol(), 2));
|
||||
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.sol(), 10));
|
||||
scripts.setupSerializableTimer(TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.sol(), 20));
|
||||
scripts.setupSerializableTimer(
|
||||
TimerType::SIMULATION_TIME, 10, test1Id, "B", sol::make_object(mLua.unsafeState(), 3));
|
||||
scripts.setupSerializableTimer(TimerType::GAME_TIME, 10, test2Id, "B", sol::make_object(mLua.unsafeState(), 4));
|
||||
scripts.setupSerializableTimer(
|
||||
TimerType::SIMULATION_TIME, 5, test1Id, "A", sol::make_object(mLua.unsafeState(), 1));
|
||||
scripts.setupSerializableTimer(TimerType::GAME_TIME, 5, test2Id, "A", sol::make_object(mLua.unsafeState(), 2));
|
||||
scripts.setupSerializableTimer(
|
||||
TimerType::SIMULATION_TIME, 15, test1Id, "A", sol::make_object(mLua.unsafeState(), 10));
|
||||
scripts.setupSerializableTimer(
|
||||
TimerType::SIMULATION_TIME, 15, test1Id, "B", sol::make_object(mLua.unsafeState(), 20));
|
||||
|
||||
scripts.setupUnsavableTimer(TimerType::SIMULATION_TIME, 10, test2Id, fn2);
|
||||
scripts.setupUnsavableTimer(TimerType::GAME_TIME, 10, test1Id, fn2);
|
||||
@ -446,7 +453,8 @@ CUSTOM, PLAYER: useInterface.lua
|
||||
|
||||
TEST_F(LuaScriptsContainerTest, CallbackWrapper)
|
||||
{
|
||||
LuaUtil::Callback callback{ mLua.sol()["print"], mLua.newTable() };
|
||||
sol::state_view view = mLua.unsafeState();
|
||||
LuaUtil::Callback callback{ view["print"], sol::table(view, sol::create) };
|
||||
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptDebugNameKey] = "some_script.lua";
|
||||
callback.mHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{ nullptr, 0 };
|
||||
|
||||
|
@ -19,102 +19,110 @@ namespace
|
||||
{
|
||||
// Note: LuaUtil::Callback can be used only if Lua is initialized via LuaUtil::LuaState
|
||||
LuaUtil::LuaState luaState{ nullptr, nullptr };
|
||||
sol::state_view& mLua = luaState.sol();
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
luaState.protectedCall([](LuaUtil::LuaView& view) {
|
||||
sol::state_view& lua = view.sol();
|
||||
LuaUtil::LuaStorage::initLuaBindings(view);
|
||||
LuaUtil::LuaStorage storage;
|
||||
storage.setActive(true);
|
||||
|
||||
sol::table callbackHiddenData(mLua, sol::create);
|
||||
callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
|
||||
LuaUtil::getAsyncPackageInitializer(
|
||||
mLua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData);
|
||||
mLua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData };
|
||||
sol::table callbackHiddenData(lua, sol::create);
|
||||
callbackHiddenData[LuaUtil::ScriptsContainer::sScriptIdKey] = LuaUtil::ScriptId{};
|
||||
LuaUtil::getAsyncPackageInitializer(
|
||||
lua.lua_state(), []() { return 0.0; }, []() { return 0.0; })(callbackHiddenData);
|
||||
lua["async"] = LuaUtil::AsyncPackageId{ nullptr, 0, callbackHiddenData };
|
||||
|
||||
mLua["mutable"] = storage.getMutableSection("test");
|
||||
mLua["ro"] = storage.getReadOnlySection("test");
|
||||
lua["mutable"] = storage.getMutableSection(lua, "test");
|
||||
lua["ro"] = storage.getReadOnlySection(lua, "test");
|
||||
|
||||
mLua.safe_script(R"(
|
||||
callbackCalls = {}
|
||||
ro:subscribe(async:callback(function(section, key)
|
||||
table.insert(callbackCalls, section .. '_' .. (key or '*'))
|
||||
end))
|
||||
)");
|
||||
lua.safe_script(R"(
|
||||
callbackCalls = {}
|
||||
ro:subscribe(async:callback(function(section, key)
|
||||
table.insert(callbackCalls, section .. '_' .. (key or '*'))
|
||||
end))
|
||||
)");
|
||||
|
||||
mLua.safe_script("mutable:set('x', 5)");
|
||||
EXPECT_EQ(get<int>(mLua, "mutable:get('x')"), 5);
|
||||
EXPECT_EQ(get<int>(mLua, "ro:get('x')"), 5);
|
||||
lua.safe_script("mutable:set('x', 5)");
|
||||
EXPECT_EQ(get<int>(lua, "mutable:get('x')"), 5);
|
||||
EXPECT_EQ(get<int>(lua, "ro:get('x')"), 5);
|
||||
|
||||
EXPECT_THROW(mLua.safe_script("ro:set('y', 3)"), std::exception);
|
||||
EXPECT_THROW(lua.safe_script("ro:set('y', 3)"), std::exception);
|
||||
|
||||
mLua.safe_script("t1 = mutable:asTable()");
|
||||
mLua.safe_script("t2 = ro:asTable()");
|
||||
EXPECT_EQ(get<int>(mLua, "t1.x"), 5);
|
||||
EXPECT_EQ(get<int>(mLua, "t2.x"), 5);
|
||||
lua.safe_script("t1 = mutable:asTable()");
|
||||
lua.safe_script("t2 = ro:asTable()");
|
||||
EXPECT_EQ(get<int>(lua, "t1.x"), 5);
|
||||
EXPECT_EQ(get<int>(lua, "t2.x"), 5);
|
||||
|
||||
mLua.safe_script("mutable:reset()");
|
||||
EXPECT_TRUE(get<bool>(mLua, "ro:get('x') == nil"));
|
||||
lua.safe_script("mutable:reset()");
|
||||
EXPECT_TRUE(get<bool>(lua, "ro:get('x') == nil"));
|
||||
|
||||
mLua.safe_script("mutable:reset({x=4, y=7})");
|
||||
EXPECT_EQ(get<int>(mLua, "ro:get('x')"), 4);
|
||||
EXPECT_EQ(get<int>(mLua, "ro:get('y')"), 7);
|
||||
lua.safe_script("mutable:reset({x=4, y=7})");
|
||||
EXPECT_EQ(get<int>(lua, "ro:get('x')"), 4);
|
||||
EXPECT_EQ(get<int>(lua, "ro:get('y')"), 7);
|
||||
|
||||
EXPECT_THAT(get<std::string>(mLua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*");
|
||||
EXPECT_THAT(get<std::string>(lua, "table.concat(callbackCalls, ', ')"), "test_x, test_*, test_*");
|
||||
});
|
||||
}
|
||||
|
||||
TEST(LuaUtilStorageTest, Table)
|
||||
{
|
||||
sol::state mLua;
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
mLua["mutable"] = storage.getMutableSection("test");
|
||||
mLua["ro"] = storage.getReadOnlySection("test");
|
||||
LuaUtil::LuaState luaState{ nullptr, nullptr };
|
||||
luaState.protectedCall([](LuaUtil::LuaView& view) {
|
||||
LuaUtil::LuaStorage::initLuaBindings(view);
|
||||
LuaUtil::LuaStorage storage;
|
||||
auto& lua = view.sol();
|
||||
storage.setActive(true);
|
||||
lua["mutable"] = storage.getMutableSection(lua, "test");
|
||||
lua["ro"] = storage.getReadOnlySection(lua, "test");
|
||||
|
||||
mLua.safe_script("mutable:set('x', { y = 'abc', z = 7 })");
|
||||
EXPECT_EQ(get<int>(mLua, "mutable:get('x').z"), 7);
|
||||
EXPECT_THROW(mLua.safe_script("mutable:get('x').z = 3"), std::exception);
|
||||
EXPECT_NO_THROW(mLua.safe_script("mutable:getCopy('x').z = 3"));
|
||||
EXPECT_EQ(get<int>(mLua, "mutable:get('x').z"), 7);
|
||||
EXPECT_EQ(get<int>(mLua, "ro:get('x').z"), 7);
|
||||
EXPECT_EQ(get<std::string>(mLua, "ro:get('x').y"), "abc");
|
||||
lua.safe_script("mutable:set('x', { y = 'abc', z = 7 })");
|
||||
EXPECT_EQ(get<int>(lua, "mutable:get('x').z"), 7);
|
||||
EXPECT_THROW(lua.safe_script("mutable:get('x').z = 3"), std::exception);
|
||||
EXPECT_NO_THROW(lua.safe_script("mutable:getCopy('x').z = 3"));
|
||||
EXPECT_EQ(get<int>(lua, "mutable:get('x').z"), 7);
|
||||
EXPECT_EQ(get<int>(lua, "ro:get('x').z"), 7);
|
||||
EXPECT_EQ(get<std::string>(lua, "ro:get('x').y"), "abc");
|
||||
});
|
||||
}
|
||||
|
||||
TEST(LuaUtilStorageTest, Saving)
|
||||
{
|
||||
sol::state mLua;
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua);
|
||||
LuaUtil::LuaStorage storage(mLua);
|
||||
storage.setActive(true);
|
||||
LuaUtil::LuaState luaState{ nullptr, nullptr };
|
||||
luaState.protectedCall([](LuaUtil::LuaView& view) {
|
||||
LuaUtil::LuaStorage::initLuaBindings(view);
|
||||
LuaUtil::LuaStorage storage;
|
||||
auto& lua = view.sol();
|
||||
storage.setActive(true);
|
||||
|
||||
mLua["permanent"] = storage.getMutableSection("permanent");
|
||||
mLua["temporary"] = storage.getMutableSection("temporary");
|
||||
mLua.safe_script("temporary:removeOnExit()");
|
||||
mLua.safe_script("permanent:set('x', 1)");
|
||||
mLua.safe_script("temporary:set('y', 2)");
|
||||
lua["permanent"] = storage.getMutableSection(lua, "permanent");
|
||||
lua["temporary"] = storage.getMutableSection(lua, "temporary");
|
||||
lua.safe_script("temporary:removeOnExit()");
|
||||
lua.safe_script("permanent:set('x', 1)");
|
||||
lua.safe_script("temporary:set('y', 2)");
|
||||
|
||||
const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin";
|
||||
storage.save(tmpFile);
|
||||
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
|
||||
EXPECT_EQ(get<int>(mLua, "temporary:get('y')"), 2);
|
||||
const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin";
|
||||
storage.save(lua, tmpFile);
|
||||
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
|
||||
EXPECT_EQ(get<int>(lua, "temporary:get('y')"), 2);
|
||||
|
||||
storage.clearTemporaryAndRemoveCallbacks();
|
||||
mLua["permanent"] = storage.getMutableSection("permanent");
|
||||
mLua["temporary"] = storage.getMutableSection("temporary");
|
||||
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
|
||||
EXPECT_TRUE(get<bool>(mLua, "temporary:get('y') == nil"));
|
||||
storage.clearTemporaryAndRemoveCallbacks();
|
||||
lua["permanent"] = storage.getMutableSection(lua, "permanent");
|
||||
lua["temporary"] = storage.getMutableSection(lua, "temporary");
|
||||
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
|
||||
EXPECT_TRUE(get<bool>(lua, "temporary:get('y') == nil"));
|
||||
|
||||
mLua.safe_script("permanent:set('x', 3)");
|
||||
mLua.safe_script("permanent:set('z', 4)");
|
||||
lua.safe_script("permanent:set('x', 3)");
|
||||
lua.safe_script("permanent:set('z', 4)");
|
||||
|
||||
LuaUtil::LuaStorage storage2(mLua);
|
||||
storage2.setActive(true);
|
||||
storage2.load(tmpFile);
|
||||
mLua["permanent"] = storage2.getMutableSection("permanent");
|
||||
mLua["temporary"] = storage2.getMutableSection("temporary");
|
||||
LuaUtil::LuaStorage storage2;
|
||||
storage2.setActive(true);
|
||||
storage2.load(lua, tmpFile);
|
||||
lua["permanent"] = storage2.getMutableSection(lua, "permanent");
|
||||
lua["temporary"] = storage2.getMutableSection(lua, "temporary");
|
||||
|
||||
EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
|
||||
EXPECT_TRUE(get<bool>(mLua, "permanent:get('z') == nil"));
|
||||
EXPECT_TRUE(get<bool>(mLua, "temporary:get('y') == nil"));
|
||||
EXPECT_EQ(get<int>(lua, "permanent:get('x')"), 1);
|
||||
EXPECT_TRUE(get<bool>(lua, "permanent:get('z') == nil"));
|
||||
EXPECT_TRUE(get<bool>(lua, "temporary:get('y') == nil"));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace
|
||||
return LuaUi::ContentView(result.get<sol::table>());
|
||||
}
|
||||
|
||||
sol::table makeTable() { return sol::table(mLuaState.sol(), sol::create); }
|
||||
sol::table makeTable() { return sol::table(mLuaState.unsafeState(), sol::create); }
|
||||
|
||||
sol::table makeTable(std::string name)
|
||||
{
|
||||
@ -39,13 +39,14 @@ namespace
|
||||
|
||||
TEST_F(LuaUiContentTest, ProtectedMetatable)
|
||||
{
|
||||
mLuaState.sol()["makeContent"] = mNew;
|
||||
mLuaState.sol()["M"] = makeContent(makeTable()).getMetatable();
|
||||
sol::state_view sol = mLuaState.unsafeState();
|
||||
sol["makeContent"] = mNew;
|
||||
sol["M"] = makeContent(makeTable()).getMetatable();
|
||||
std::string testScript = R"(
|
||||
assert(not pcall(function() setmetatable(makeContent{}, {}) end), 'Metatable is not protected')
|
||||
assert(getmetatable(makeContent{}) == false, 'Metatable is not protected')
|
||||
)";
|
||||
EXPECT_NO_THROW(mLuaState.sol().safe_script(testScript));
|
||||
EXPECT_NO_THROW(sol.safe_script(testScript));
|
||||
}
|
||||
|
||||
TEST_F(LuaUiContentTest, Create)
|
||||
|
@ -99,45 +99,48 @@ namespace MWLua
|
||||
|
||||
sol::table initAnimationPackage(const Context& context)
|
||||
{
|
||||
auto* lua = context.mLua;
|
||||
auto view = context.sol();
|
||||
auto mechanics = MWBase::Environment::get().getMechanicsManager();
|
||||
auto world = MWBase::Environment::get().getWorld();
|
||||
|
||||
sol::table api(lua->sol(), sol::create);
|
||||
sol::table api(view, sol::create);
|
||||
|
||||
api["PRIORITY"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWMechanics::Priority>({
|
||||
{ "Default", MWMechanics::Priority::Priority_Default },
|
||||
{ "WeaponLowerBody", MWMechanics::Priority::Priority_WeaponLowerBody },
|
||||
{ "SneakIdleLowerBody", MWMechanics::Priority::Priority_SneakIdleLowerBody },
|
||||
{ "SwimIdle", MWMechanics::Priority::Priority_SwimIdle },
|
||||
{ "Jump", MWMechanics::Priority::Priority_Jump },
|
||||
{ "Movement", MWMechanics::Priority::Priority_Movement },
|
||||
{ "Hit", MWMechanics::Priority::Priority_Hit },
|
||||
{ "Weapon", MWMechanics::Priority::Priority_Weapon },
|
||||
{ "Block", MWMechanics::Priority::Priority_Block },
|
||||
{ "Knockdown", MWMechanics::Priority::Priority_Knockdown },
|
||||
{ "Torch", MWMechanics::Priority::Priority_Torch },
|
||||
{ "Storm", MWMechanics::Priority::Priority_Storm },
|
||||
{ "Death", MWMechanics::Priority::Priority_Death },
|
||||
{ "Scripted", MWMechanics::Priority::Priority_Scripted },
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWMechanics::Priority>(view,
|
||||
{
|
||||
{ "Default", MWMechanics::Priority::Priority_Default },
|
||||
{ "WeaponLowerBody", MWMechanics::Priority::Priority_WeaponLowerBody },
|
||||
{ "SneakIdleLowerBody", MWMechanics::Priority::Priority_SneakIdleLowerBody },
|
||||
{ "SwimIdle", MWMechanics::Priority::Priority_SwimIdle },
|
||||
{ "Jump", MWMechanics::Priority::Priority_Jump },
|
||||
{ "Movement", MWMechanics::Priority::Priority_Movement },
|
||||
{ "Hit", MWMechanics::Priority::Priority_Hit },
|
||||
{ "Weapon", MWMechanics::Priority::Priority_Weapon },
|
||||
{ "Block", MWMechanics::Priority::Priority_Block },
|
||||
{ "Knockdown", MWMechanics::Priority::Priority_Knockdown },
|
||||
{ "Torch", MWMechanics::Priority::Priority_Torch },
|
||||
{ "Storm", MWMechanics::Priority::Priority_Storm },
|
||||
{ "Death", MWMechanics::Priority::Priority_Death },
|
||||
{ "Scripted", MWMechanics::Priority::Priority_Scripted },
|
||||
}));
|
||||
|
||||
api["BLEND_MASK"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, BlendMask>(view,
|
||||
{
|
||||
{ "LowerBody", BlendMask::BlendMask_LowerBody },
|
||||
{ "Torso", BlendMask::BlendMask_Torso },
|
||||
{ "LeftArm", BlendMask::BlendMask_LeftArm },
|
||||
{ "RightArm", BlendMask::BlendMask_RightArm },
|
||||
{ "UpperBody", BlendMask::BlendMask_UpperBody },
|
||||
{ "All", BlendMask::BlendMask_All },
|
||||
}));
|
||||
|
||||
api["BLEND_MASK"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, BlendMask>({
|
||||
{ "LowerBody", BlendMask::BlendMask_LowerBody },
|
||||
{ "Torso", BlendMask::BlendMask_Torso },
|
||||
{ "LeftArm", BlendMask::BlendMask_LeftArm },
|
||||
{ "RightArm", BlendMask::BlendMask_RightArm },
|
||||
{ "UpperBody", BlendMask::BlendMask_UpperBody },
|
||||
{ "All", BlendMask::BlendMask_All },
|
||||
}));
|
||||
|
||||
api["BONE_GROUP"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, BoneGroup>({
|
||||
{ "LowerBody", BoneGroup::BoneGroup_LowerBody },
|
||||
{ "Torso", BoneGroup::BoneGroup_Torso },
|
||||
{ "LeftArm", BoneGroup::BoneGroup_LeftArm },
|
||||
{ "RightArm", BoneGroup::BoneGroup_RightArm },
|
||||
}));
|
||||
api["BONE_GROUP"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, BoneGroup>(view,
|
||||
{
|
||||
{ "LowerBody", BoneGroup::BoneGroup_LowerBody },
|
||||
{ "Torso", BoneGroup::BoneGroup_Torso },
|
||||
{ "LeftArm", BoneGroup::BoneGroup_LeftArm },
|
||||
{ "RightArm", BoneGroup::BoneGroup_RightArm },
|
||||
}));
|
||||
|
||||
api["hasAnimation"] = [world](const sol::object& object) -> bool {
|
||||
return world->getAnimation(getPtrOrThrow(ObjectVariant(object))) != nullptr;
|
||||
@ -305,8 +308,7 @@ namespace MWLua
|
||||
|
||||
sol::table initWorldVfxBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table api(lua, sol::create);
|
||||
sol::table api(context.mLua->unsafeState(), sol::create);
|
||||
auto world = MWBase::Environment::get().getWorld();
|
||||
|
||||
api["spawn"]
|
||||
|
@ -22,8 +22,8 @@ namespace MWLua
|
||||
{
|
||||
sol::table initBirthSignRecordBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table birthSigns(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table birthSigns(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::BirthSign>(birthSigns, context);
|
||||
|
||||
auto signT = lua.new_usertype<ESM::BirthSign>("ESM3_BirthSign");
|
||||
|
@ -14,7 +14,7 @@ namespace MWLua
|
||||
|
||||
using CameraMode = MWRender::Camera::Mode;
|
||||
|
||||
sol::table initCameraPackage(sol::state_view& lua)
|
||||
sol::table initCameraPackage(sol::state_view lua)
|
||||
{
|
||||
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
|
||||
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCameraPackage(sol::state_view& lua);
|
||||
sol::table initCameraPackage(sol::state_view lua);
|
||||
}
|
||||
|
||||
#endif // MWLUA_CAMERABINDINGS_H
|
||||
|
@ -69,7 +69,8 @@ namespace MWLua
|
||||
template <class CellT, class ObjectT>
|
||||
static void initCellBindings(const std::string& prefix, const Context& context)
|
||||
{
|
||||
sol::usertype<CellT> cellT = context.mLua->sol().new_usertype<CellT>(prefix + "Cell");
|
||||
auto view = context.sol();
|
||||
sol::usertype<CellT> cellT = view.new_usertype<CellT>(prefix + "Cell");
|
||||
|
||||
cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; };
|
||||
cellT[sol::meta_function::to_string] = [](const CellT& c) {
|
||||
@ -127,8 +128,7 @@ namespace MWLua
|
||||
|
||||
if constexpr (std::is_same_v<CellT, GCell>)
|
||||
{ // only for global scripts
|
||||
cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
|
||||
const CellT& cell, sol::optional<sol::table> type) {
|
||||
cellT["getAll"] = [ids = getPackageToTypeTable(view)](const CellT& cell, sol::optional<sol::table> type) {
|
||||
if (cell.mStore->getState() != MWWorld::CellStore::State_Loaded)
|
||||
cell.mStore->load();
|
||||
ObjectIdList res = std::make_shared<std::vector<ObjectId>>();
|
||||
|
@ -19,8 +19,8 @@ namespace MWLua
|
||||
|
||||
sol::table initClassRecordBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table classes(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table classes(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::Class>(classes, context);
|
||||
|
||||
auto classT = lua.new_usertype<ESM::Class>("ESM3_Class");
|
||||
|
@ -48,7 +48,7 @@ namespace MWLua
|
||||
template <class... Str>
|
||||
sol::object getCachedPackage(std::string_view first, const Str&... str) const
|
||||
{
|
||||
sol::object package = mLua->sol()[first];
|
||||
sol::object package = sol()[first];
|
||||
if constexpr (sizeof...(str) == 0)
|
||||
return package;
|
||||
else
|
||||
@ -58,7 +58,7 @@ namespace MWLua
|
||||
template <class... Str>
|
||||
const sol::object& setCachedPackage(const sol::object& value, std::string_view first, const Str&... str) const
|
||||
{
|
||||
sol::state_view& lua = mLua->sol();
|
||||
sol::state_view lua = sol();
|
||||
if constexpr (sizeof...(str) == 0)
|
||||
lua[first] = value;
|
||||
else
|
||||
@ -90,10 +90,17 @@ namespace MWLua
|
||||
|
||||
bool initializeOnce(std::string_view key) const
|
||||
{
|
||||
sol::object flag = mLua->sol()[key];
|
||||
mLua->sol()[key] = sol::make_object(mLua->sol(), true);
|
||||
auto view = sol();
|
||||
sol::object flag = view[key];
|
||||
view[key] = sol::make_object(view, true);
|
||||
return flag == sol::nil;
|
||||
}
|
||||
|
||||
sol::state_view sol() const
|
||||
{
|
||||
// Bindings are initialized in a safe context
|
||||
return mLua->unsafeState();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -70,19 +70,18 @@ namespace MWLua
|
||||
|
||||
sol::table initCorePackage(const Context& context)
|
||||
{
|
||||
auto* lua = context.mLua;
|
||||
|
||||
auto lua = context.sol();
|
||||
sol::object cached = context.getTypePackage("openmw_core");
|
||||
if (cached != sol::nil)
|
||||
return cached;
|
||||
|
||||
sol::table api(lua->sol(), sol::create);
|
||||
sol::table api(lua, sol::create);
|
||||
api["API_REVISION"] = Version::getLuaApiRevision(); // specified in CMakeLists.txt
|
||||
api["quit"] = [lua]() {
|
||||
api["quit"] = [lua = context.mLua]() {
|
||||
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
};
|
||||
api["contentFiles"] = initContentFilesBindings(lua->sol());
|
||||
api["contentFiles"] = initContentFilesBindings(lua);
|
||||
api["getFormId"] = [](std::string_view contentFile, unsigned int index) -> std::string {
|
||||
const std::vector<std::string>& contentList = MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
for (size_t i = 0; i < contentList.size(); ++i)
|
||||
@ -103,10 +102,10 @@ namespace MWLua
|
||||
api["dialogue"]
|
||||
= context.cachePackage("openmw_core_dialogue", [context]() { return initCoreDialogueBindings(context); });
|
||||
api["l10n"] = context.cachePackage("openmw_core_l10n",
|
||||
[lua]() { return LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager()); });
|
||||
[lua]() { return LuaUtil::initL10nLoader(lua, MWBase::Environment::get().getL10nManager()); });
|
||||
const MWWorld::Store<ESM::GameSetting>* gmstStore
|
||||
= &MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||
api["getGMST"] = [lua = context.mLua, gmstStore](const std::string& setting) -> sol::object {
|
||||
api["getGMST"] = [lua, gmstStore](const std::string& setting) -> sol::object {
|
||||
const ESM::GameSetting* gmst = gmstStore->search(setting);
|
||||
if (gmst == nullptr)
|
||||
return sol::nil;
|
||||
@ -114,13 +113,13 @@ namespace MWLua
|
||||
switch (value.getType())
|
||||
{
|
||||
case ESM::VT_Float:
|
||||
return sol::make_object<float>(lua->sol(), value.getFloat());
|
||||
return sol::make_object<float>(lua, value.getFloat());
|
||||
case ESM::VT_Short:
|
||||
case ESM::VT_Long:
|
||||
case ESM::VT_Int:
|
||||
return sol::make_object<int>(lua->sol(), value.getInteger());
|
||||
return sol::make_object<int>(lua, value.getInteger());
|
||||
case ESM::VT_String:
|
||||
return sol::make_object<std::string>(lua->sol(), value.getString());
|
||||
return sol::make_object<std::string>(lua, value.getString());
|
||||
case ESM::VT_Unknown:
|
||||
case ESM::VT_None:
|
||||
break;
|
||||
|
@ -20,19 +20,21 @@ namespace MWLua
|
||||
{
|
||||
sol::table initDebugPackage(const Context& context)
|
||||
{
|
||||
sol::table api = context.mLua->newTable();
|
||||
auto view = context.sol();
|
||||
sol::table api(view, sol::create);
|
||||
|
||||
api["RENDER_MODE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWRender::RenderMode>({
|
||||
{ "CollisionDebug", MWRender::Render_CollisionDebug },
|
||||
{ "Wireframe", MWRender::Render_Wireframe },
|
||||
{ "Pathgrid", MWRender::Render_Pathgrid },
|
||||
{ "Water", MWRender::Render_Water },
|
||||
{ "Scene", MWRender::Render_Scene },
|
||||
{ "NavMesh", MWRender::Render_NavMesh },
|
||||
{ "ActorsPaths", MWRender::Render_ActorsPaths },
|
||||
{ "RecastMesh", MWRender::Render_RecastMesh },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWRender::RenderMode>(view,
|
||||
{
|
||||
{ "CollisionDebug", MWRender::Render_CollisionDebug },
|
||||
{ "Wireframe", MWRender::Render_Wireframe },
|
||||
{ "Pathgrid", MWRender::Render_Pathgrid },
|
||||
{ "Water", MWRender::Render_Water },
|
||||
{ "Scene", MWRender::Render_Scene },
|
||||
{ "NavMesh", MWRender::Render_NavMesh },
|
||||
{ "ActorsPaths", MWRender::Render_ActorsPaths },
|
||||
{ "RecastMesh", MWRender::Render_RecastMesh },
|
||||
}));
|
||||
|
||||
api["toggleRenderMode"] = [context](MWRender::RenderMode value) {
|
||||
context.mLuaManager->addAction([value] { MWBase::Environment::get().getWorld()->toggleRenderMode(value); });
|
||||
@ -56,10 +58,11 @@ namespace MWLua
|
||||
api["reloadLua"] = []() { MWBase::Environment::get().getLuaManager()->reloadAllScripts(); };
|
||||
|
||||
api["NAV_MESH_RENDER_MODE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, Settings::NavMeshRenderMode>({
|
||||
{ "AreaType", Settings::NavMeshRenderMode::AreaType },
|
||||
{ "UpdateFrequency", Settings::NavMeshRenderMode::UpdateFrequency },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, Settings::NavMeshRenderMode>(view,
|
||||
{
|
||||
{ "AreaType", Settings::NavMeshRenderMode::AreaType },
|
||||
{ "UpdateFrequency", Settings::NavMeshRenderMode::UpdateFrequency },
|
||||
}));
|
||||
|
||||
api["setNavMeshRenderMode"] = [context](Settings::NavMeshRenderMode value) {
|
||||
context.mLuaManager->addAction(
|
||||
|
@ -59,7 +59,7 @@ namespace
|
||||
{
|
||||
using StoreT = FilteredDialogueStore<filter>;
|
||||
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::usertype<StoreT> storeBindingsClass
|
||||
= lua.new_usertype<StoreT>("ESM3_Dialogue_Type" + std::to_string(filter) + " Store");
|
||||
storeBindingsClass[sol::meta_function::to_string] = [](const StoreT& store) {
|
||||
@ -317,7 +317,7 @@ namespace MWLua
|
||||
{
|
||||
sol::table initCoreDialogueBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
sol::table journalTable(lua, sol::create);
|
||||
|
@ -46,7 +46,7 @@ namespace MWLua
|
||||
{
|
||||
sol::table initCoreFactionBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table factions(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::Faction>(factions, context);
|
||||
// Faction record
|
||||
|
@ -38,13 +38,13 @@ namespace MWLua
|
||||
|
||||
sol::table initInputPackage(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
if (lua["openmw_input"] != sol::nil)
|
||||
return lua["openmw_input"];
|
||||
}
|
||||
|
||||
sol::usertype<SDL_Keysym> keyEvent = context.mLua->sol().new_usertype<SDL_Keysym>("KeyEvent");
|
||||
sol::usertype<SDL_Keysym> keyEvent = lua.new_usertype<SDL_Keysym>("KeyEvent");
|
||||
keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) {
|
||||
if (e.sym > 0 && e.sym <= 255)
|
||||
return std::string(1, static_cast<char>(e.sym));
|
||||
@ -57,7 +57,7 @@ namespace MWLua
|
||||
keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; });
|
||||
keyEvent["withSuper"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; });
|
||||
|
||||
auto touchpadEvent = context.mLua->sol().new_usertype<SDLUtil::TouchEvent>("TouchpadEvent");
|
||||
auto touchpadEvent = lua.new_usertype<SDLUtil::TouchEvent>("TouchpadEvent");
|
||||
touchpadEvent["device"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; });
|
||||
touchpadEvent["finger"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; });
|
||||
touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f {
|
||||
@ -66,7 +66,7 @@ namespace MWLua
|
||||
touchpadEvent["pressure"]
|
||||
= sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; });
|
||||
|
||||
auto inputActions = context.mLua->sol().new_usertype<LuaUtil::InputAction::Registry>("InputActions");
|
||||
auto inputActions = lua.new_usertype<LuaUtil::InputAction::Registry>("InputActions");
|
||||
inputActions[sol::meta_function::index]
|
||||
= [](LuaUtil::InputAction::Registry& registry, std::string_view key) { return registry[key]; };
|
||||
{
|
||||
@ -85,7 +85,7 @@ namespace MWLua
|
||||
inputActions[sol::meta_function::pairs] = pairs;
|
||||
}
|
||||
|
||||
auto actionInfo = context.mLua->sol().new_usertype<LuaUtil::InputAction::Info>("ActionInfo");
|
||||
auto actionInfo = lua.new_usertype<LuaUtil::InputAction::Info>("ActionInfo");
|
||||
actionInfo["key"] = sol::readonly_property(
|
||||
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mKey; });
|
||||
actionInfo["name"] = sol::readonly_property(
|
||||
@ -98,7 +98,7 @@ namespace MWLua
|
||||
actionInfo["defaultValue"]
|
||||
= sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mDefaultValue; });
|
||||
|
||||
auto inputTriggers = context.mLua->sol().new_usertype<LuaUtil::InputTrigger::Registry>("InputTriggers");
|
||||
auto inputTriggers = lua.new_usertype<LuaUtil::InputTrigger::Registry>("InputTriggers");
|
||||
inputTriggers[sol::meta_function::index]
|
||||
= [](LuaUtil::InputTrigger::Registry& registry, std::string_view key) { return registry[key]; };
|
||||
{
|
||||
@ -117,7 +117,7 @@ namespace MWLua
|
||||
inputTriggers[sol::meta_function::pairs] = pairs;
|
||||
}
|
||||
|
||||
auto triggerInfo = context.mLua->sol().new_usertype<LuaUtil::InputTrigger::Info>("TriggerInfo");
|
||||
auto triggerInfo = lua.new_usertype<LuaUtil::InputTrigger::Info>("TriggerInfo");
|
||||
triggerInfo["key"] = sol::readonly_property(
|
||||
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mKey; });
|
||||
triggerInfo["name"] = sol::readonly_property(
|
||||
@ -128,14 +128,15 @@ namespace MWLua
|
||||
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mL10n; });
|
||||
|
||||
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
api["ACTION_TYPE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, LuaUtil::InputAction::Type>({
|
||||
{ "Boolean", LuaUtil::InputAction::Type::Boolean },
|
||||
{ "Number", LuaUtil::InputAction::Type::Number },
|
||||
{ "Range", LuaUtil::InputAction::Type::Range },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, LuaUtil::InputAction::Type>(lua,
|
||||
{
|
||||
{ "Boolean", LuaUtil::InputAction::Type::Boolean },
|
||||
{ "Number", LuaUtil::InputAction::Type::Number },
|
||||
{ "Range", LuaUtil::InputAction::Type::Range },
|
||||
}));
|
||||
|
||||
api["actions"] = std::ref(context.mLuaManager->inputActions());
|
||||
api["registerAction"] = [manager = context.mLuaManager](sol::table options) {
|
||||
@ -231,215 +232,219 @@ namespace MWLua
|
||||
|
||||
api["getKeyName"] = [](SDL_Scancode code) { return SDL_GetScancodeName(code); };
|
||||
|
||||
api["ACTION"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWInput::Actions>({
|
||||
{ "GameMenu", MWInput::A_GameMenu },
|
||||
{ "Screenshot", MWInput::A_Screenshot },
|
||||
{ "Inventory", MWInput::A_Inventory },
|
||||
{ "Console", MWInput::A_Console },
|
||||
api["ACTION"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWInput::Actions>(lua,
|
||||
{
|
||||
{ "GameMenu", MWInput::A_GameMenu },
|
||||
{ "Screenshot", MWInput::A_Screenshot },
|
||||
{ "Inventory", MWInput::A_Inventory },
|
||||
{ "Console", MWInput::A_Console },
|
||||
|
||||
{ "MoveLeft", MWInput::A_MoveLeft },
|
||||
{ "MoveRight", MWInput::A_MoveRight },
|
||||
{ "MoveForward", MWInput::A_MoveForward },
|
||||
{ "MoveBackward", MWInput::A_MoveBackward },
|
||||
{ "MoveLeft", MWInput::A_MoveLeft },
|
||||
{ "MoveRight", MWInput::A_MoveRight },
|
||||
{ "MoveForward", MWInput::A_MoveForward },
|
||||
{ "MoveBackward", MWInput::A_MoveBackward },
|
||||
|
||||
{ "Activate", MWInput::A_Activate },
|
||||
{ "Use", MWInput::A_Use },
|
||||
{ "Jump", MWInput::A_Jump },
|
||||
{ "AutoMove", MWInput::A_AutoMove },
|
||||
{ "Rest", MWInput::A_Rest },
|
||||
{ "Journal", MWInput::A_Journal },
|
||||
{ "Run", MWInput::A_Run },
|
||||
{ "CycleSpellLeft", MWInput::A_CycleSpellLeft },
|
||||
{ "CycleSpellRight", MWInput::A_CycleSpellRight },
|
||||
{ "CycleWeaponLeft", MWInput::A_CycleWeaponLeft },
|
||||
{ "CycleWeaponRight", MWInput::A_CycleWeaponRight },
|
||||
{ "AlwaysRun", MWInput::A_AlwaysRun },
|
||||
{ "Sneak", MWInput::A_Sneak },
|
||||
{ "Activate", MWInput::A_Activate },
|
||||
{ "Use", MWInput::A_Use },
|
||||
{ "Jump", MWInput::A_Jump },
|
||||
{ "AutoMove", MWInput::A_AutoMove },
|
||||
{ "Rest", MWInput::A_Rest },
|
||||
{ "Journal", MWInput::A_Journal },
|
||||
{ "Run", MWInput::A_Run },
|
||||
{ "CycleSpellLeft", MWInput::A_CycleSpellLeft },
|
||||
{ "CycleSpellRight", MWInput::A_CycleSpellRight },
|
||||
{ "CycleWeaponLeft", MWInput::A_CycleWeaponLeft },
|
||||
{ "CycleWeaponRight", MWInput::A_CycleWeaponRight },
|
||||
{ "AlwaysRun", MWInput::A_AlwaysRun },
|
||||
{ "Sneak", MWInput::A_Sneak },
|
||||
|
||||
{ "QuickSave", MWInput::A_QuickSave },
|
||||
{ "QuickLoad", MWInput::A_QuickLoad },
|
||||
{ "QuickMenu", MWInput::A_QuickMenu },
|
||||
{ "ToggleWeapon", MWInput::A_ToggleWeapon },
|
||||
{ "ToggleSpell", MWInput::A_ToggleSpell },
|
||||
{ "TogglePOV", MWInput::A_TogglePOV },
|
||||
{ "QuickSave", MWInput::A_QuickSave },
|
||||
{ "QuickLoad", MWInput::A_QuickLoad },
|
||||
{ "QuickMenu", MWInput::A_QuickMenu },
|
||||
{ "ToggleWeapon", MWInput::A_ToggleWeapon },
|
||||
{ "ToggleSpell", MWInput::A_ToggleSpell },
|
||||
{ "TogglePOV", MWInput::A_TogglePOV },
|
||||
|
||||
{ "QuickKey1", MWInput::A_QuickKey1 },
|
||||
{ "QuickKey2", MWInput::A_QuickKey2 },
|
||||
{ "QuickKey3", MWInput::A_QuickKey3 },
|
||||
{ "QuickKey4", MWInput::A_QuickKey4 },
|
||||
{ "QuickKey5", MWInput::A_QuickKey5 },
|
||||
{ "QuickKey6", MWInput::A_QuickKey6 },
|
||||
{ "QuickKey7", MWInput::A_QuickKey7 },
|
||||
{ "QuickKey8", MWInput::A_QuickKey8 },
|
||||
{ "QuickKey9", MWInput::A_QuickKey9 },
|
||||
{ "QuickKey10", MWInput::A_QuickKey10 },
|
||||
{ "QuickKeysMenu", MWInput::A_QuickKeysMenu },
|
||||
{ "QuickKey1", MWInput::A_QuickKey1 },
|
||||
{ "QuickKey2", MWInput::A_QuickKey2 },
|
||||
{ "QuickKey3", MWInput::A_QuickKey3 },
|
||||
{ "QuickKey4", MWInput::A_QuickKey4 },
|
||||
{ "QuickKey5", MWInput::A_QuickKey5 },
|
||||
{ "QuickKey6", MWInput::A_QuickKey6 },
|
||||
{ "QuickKey7", MWInput::A_QuickKey7 },
|
||||
{ "QuickKey8", MWInput::A_QuickKey8 },
|
||||
{ "QuickKey9", MWInput::A_QuickKey9 },
|
||||
{ "QuickKey10", MWInput::A_QuickKey10 },
|
||||
{ "QuickKeysMenu", MWInput::A_QuickKeysMenu },
|
||||
|
||||
{ "ToggleHUD", MWInput::A_ToggleHUD },
|
||||
{ "ToggleDebug", MWInput::A_ToggleDebug },
|
||||
{ "TogglePostProcessorHUD", MWInput::A_TogglePostProcessorHUD },
|
||||
{ "ToggleHUD", MWInput::A_ToggleHUD },
|
||||
{ "ToggleDebug", MWInput::A_ToggleDebug },
|
||||
{ "TogglePostProcessorHUD", MWInput::A_TogglePostProcessorHUD },
|
||||
|
||||
{ "ZoomIn", MWInput::A_ZoomIn },
|
||||
{ "ZoomOut", MWInput::A_ZoomOut },
|
||||
}));
|
||||
{ "ZoomIn", MWInput::A_ZoomIn },
|
||||
{ "ZoomOut", MWInput::A_ZoomOut },
|
||||
}));
|
||||
|
||||
// input.CONTROL_SWITCH is deprecated, remove after releasing 0.49
|
||||
api["CONTROL_SWITCH"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, std::string_view>({
|
||||
{ "Controls", "playercontrols" },
|
||||
{ "Fighting", "playerfighting" },
|
||||
{ "Jumping", "playerjumping" },
|
||||
{ "Looking", "playerlooking" },
|
||||
{ "Magic", "playermagic" },
|
||||
{ "ViewMode", "playerviewswitch" },
|
||||
{ "VanityMode", "vanitymode" },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, std::string_view>(lua,
|
||||
{
|
||||
{ "Controls", "playercontrols" },
|
||||
{ "Fighting", "playerfighting" },
|
||||
{ "Jumping", "playerjumping" },
|
||||
{ "Looking", "playerlooking" },
|
||||
{ "Magic", "playermagic" },
|
||||
{ "ViewMode", "playerviewswitch" },
|
||||
{ "VanityMode", "vanitymode" },
|
||||
}));
|
||||
|
||||
api["CONTROLLER_BUTTON"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_GameControllerButton>({
|
||||
{ "A", SDL_CONTROLLER_BUTTON_A },
|
||||
{ "B", SDL_CONTROLLER_BUTTON_B },
|
||||
{ "X", SDL_CONTROLLER_BUTTON_X },
|
||||
{ "Y", SDL_CONTROLLER_BUTTON_Y },
|
||||
{ "Back", SDL_CONTROLLER_BUTTON_BACK },
|
||||
{ "Guide", SDL_CONTROLLER_BUTTON_GUIDE },
|
||||
{ "Start", SDL_CONTROLLER_BUTTON_START },
|
||||
{ "LeftStick", SDL_CONTROLLER_BUTTON_LEFTSTICK },
|
||||
{ "RightStick", SDL_CONTROLLER_BUTTON_RIGHTSTICK },
|
||||
{ "LeftShoulder", SDL_CONTROLLER_BUTTON_LEFTSHOULDER },
|
||||
{ "RightShoulder", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER },
|
||||
{ "DPadUp", SDL_CONTROLLER_BUTTON_DPAD_UP },
|
||||
{ "DPadDown", SDL_CONTROLLER_BUTTON_DPAD_DOWN },
|
||||
{ "DPadLeft", SDL_CONTROLLER_BUTTON_DPAD_LEFT },
|
||||
{ "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT },
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, SDL_GameControllerButton>(lua,
|
||||
{
|
||||
{ "A", SDL_CONTROLLER_BUTTON_A },
|
||||
{ "B", SDL_CONTROLLER_BUTTON_B },
|
||||
{ "X", SDL_CONTROLLER_BUTTON_X },
|
||||
{ "Y", SDL_CONTROLLER_BUTTON_Y },
|
||||
{ "Back", SDL_CONTROLLER_BUTTON_BACK },
|
||||
{ "Guide", SDL_CONTROLLER_BUTTON_GUIDE },
|
||||
{ "Start", SDL_CONTROLLER_BUTTON_START },
|
||||
{ "LeftStick", SDL_CONTROLLER_BUTTON_LEFTSTICK },
|
||||
{ "RightStick", SDL_CONTROLLER_BUTTON_RIGHTSTICK },
|
||||
{ "LeftShoulder", SDL_CONTROLLER_BUTTON_LEFTSHOULDER },
|
||||
{ "RightShoulder", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER },
|
||||
{ "DPadUp", SDL_CONTROLLER_BUTTON_DPAD_UP },
|
||||
{ "DPadDown", SDL_CONTROLLER_BUTTON_DPAD_DOWN },
|
||||
{ "DPadLeft", SDL_CONTROLLER_BUTTON_DPAD_LEFT },
|
||||
{ "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT },
|
||||
}));
|
||||
|
||||
api["CONTROLLER_AXIS"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "LeftX", SDL_CONTROLLER_AXIS_LEFTX },
|
||||
{ "LeftY", SDL_CONTROLLER_AXIS_LEFTY },
|
||||
{ "RightX", SDL_CONTROLLER_AXIS_RIGHTX },
|
||||
{ "RightY", SDL_CONTROLLER_AXIS_RIGHTY },
|
||||
{ "TriggerLeft", SDL_CONTROLLER_AXIS_TRIGGERLEFT },
|
||||
{ "TriggerRight", SDL_CONTROLLER_AXIS_TRIGGERRIGHT },
|
||||
|
||||
{ "LookUpDown", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_LookUpDown) },
|
||||
{ "LookLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_LookLeftRight) },
|
||||
{ "MoveForwardBackward", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveForwardBackward) },
|
||||
{ "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveLeftRight) },
|
||||
}));
|
||||
|
||||
api["CONTROLLER_AXIS"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "LeftX", SDL_CONTROLLER_AXIS_LEFTX },
|
||||
{ "LeftY", SDL_CONTROLLER_AXIS_LEFTY },
|
||||
{ "RightX", SDL_CONTROLLER_AXIS_RIGHTX },
|
||||
{ "RightY", SDL_CONTROLLER_AXIS_RIGHTY },
|
||||
{ "TriggerLeft", SDL_CONTROLLER_AXIS_TRIGGERLEFT },
|
||||
{ "TriggerRight", SDL_CONTROLLER_AXIS_TRIGGERRIGHT },
|
||||
api["KEY"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, SDL_Scancode>(lua,
|
||||
{
|
||||
{ "_0", SDL_SCANCODE_0 },
|
||||
{ "_1", SDL_SCANCODE_1 },
|
||||
{ "_2", SDL_SCANCODE_2 },
|
||||
{ "_3", SDL_SCANCODE_3 },
|
||||
{ "_4", SDL_SCANCODE_4 },
|
||||
{ "_5", SDL_SCANCODE_5 },
|
||||
{ "_6", SDL_SCANCODE_6 },
|
||||
{ "_7", SDL_SCANCODE_7 },
|
||||
{ "_8", SDL_SCANCODE_8 },
|
||||
{ "_9", SDL_SCANCODE_9 },
|
||||
|
||||
{ "LookUpDown", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_LookUpDown) },
|
||||
{ "LookLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_LookLeftRight) },
|
||||
{ "MoveForwardBackward", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveForwardBackward) },
|
||||
{ "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveLeftRight) },
|
||||
}));
|
||||
{ "NP_0", SDL_SCANCODE_KP_0 },
|
||||
{ "NP_1", SDL_SCANCODE_KP_1 },
|
||||
{ "NP_2", SDL_SCANCODE_KP_2 },
|
||||
{ "NP_3", SDL_SCANCODE_KP_3 },
|
||||
{ "NP_4", SDL_SCANCODE_KP_4 },
|
||||
{ "NP_5", SDL_SCANCODE_KP_5 },
|
||||
{ "NP_6", SDL_SCANCODE_KP_6 },
|
||||
{ "NP_7", SDL_SCANCODE_KP_7 },
|
||||
{ "NP_8", SDL_SCANCODE_KP_8 },
|
||||
{ "NP_9", SDL_SCANCODE_KP_9 },
|
||||
{ "NP_Divide", SDL_SCANCODE_KP_DIVIDE },
|
||||
{ "NP_Enter", SDL_SCANCODE_KP_ENTER },
|
||||
{ "NP_Minus", SDL_SCANCODE_KP_MINUS },
|
||||
{ "NP_Multiply", SDL_SCANCODE_KP_MULTIPLY },
|
||||
{ "NP_Delete", SDL_SCANCODE_KP_PERIOD },
|
||||
{ "NP_Plus", SDL_SCANCODE_KP_PLUS },
|
||||
|
||||
api["KEY"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_Scancode>({
|
||||
{ "_0", SDL_SCANCODE_0 },
|
||||
{ "_1", SDL_SCANCODE_1 },
|
||||
{ "_2", SDL_SCANCODE_2 },
|
||||
{ "_3", SDL_SCANCODE_3 },
|
||||
{ "_4", SDL_SCANCODE_4 },
|
||||
{ "_5", SDL_SCANCODE_5 },
|
||||
{ "_6", SDL_SCANCODE_6 },
|
||||
{ "_7", SDL_SCANCODE_7 },
|
||||
{ "_8", SDL_SCANCODE_8 },
|
||||
{ "_9", SDL_SCANCODE_9 },
|
||||
{ "F1", SDL_SCANCODE_F1 },
|
||||
{ "F2", SDL_SCANCODE_F2 },
|
||||
{ "F3", SDL_SCANCODE_F3 },
|
||||
{ "F4", SDL_SCANCODE_F4 },
|
||||
{ "F5", SDL_SCANCODE_F5 },
|
||||
{ "F6", SDL_SCANCODE_F6 },
|
||||
{ "F7", SDL_SCANCODE_F7 },
|
||||
{ "F8", SDL_SCANCODE_F8 },
|
||||
{ "F9", SDL_SCANCODE_F9 },
|
||||
{ "F10", SDL_SCANCODE_F10 },
|
||||
{ "F11", SDL_SCANCODE_F11 },
|
||||
{ "F12", SDL_SCANCODE_F12 },
|
||||
|
||||
{ "NP_0", SDL_SCANCODE_KP_0 },
|
||||
{ "NP_1", SDL_SCANCODE_KP_1 },
|
||||
{ "NP_2", SDL_SCANCODE_KP_2 },
|
||||
{ "NP_3", SDL_SCANCODE_KP_3 },
|
||||
{ "NP_4", SDL_SCANCODE_KP_4 },
|
||||
{ "NP_5", SDL_SCANCODE_KP_5 },
|
||||
{ "NP_6", SDL_SCANCODE_KP_6 },
|
||||
{ "NP_7", SDL_SCANCODE_KP_7 },
|
||||
{ "NP_8", SDL_SCANCODE_KP_8 },
|
||||
{ "NP_9", SDL_SCANCODE_KP_9 },
|
||||
{ "NP_Divide", SDL_SCANCODE_KP_DIVIDE },
|
||||
{ "NP_Enter", SDL_SCANCODE_KP_ENTER },
|
||||
{ "NP_Minus", SDL_SCANCODE_KP_MINUS },
|
||||
{ "NP_Multiply", SDL_SCANCODE_KP_MULTIPLY },
|
||||
{ "NP_Delete", SDL_SCANCODE_KP_PERIOD },
|
||||
{ "NP_Plus", SDL_SCANCODE_KP_PLUS },
|
||||
{ "A", SDL_SCANCODE_A },
|
||||
{ "B", SDL_SCANCODE_B },
|
||||
{ "C", SDL_SCANCODE_C },
|
||||
{ "D", SDL_SCANCODE_D },
|
||||
{ "E", SDL_SCANCODE_E },
|
||||
{ "F", SDL_SCANCODE_F },
|
||||
{ "G", SDL_SCANCODE_G },
|
||||
{ "H", SDL_SCANCODE_H },
|
||||
{ "I", SDL_SCANCODE_I },
|
||||
{ "J", SDL_SCANCODE_J },
|
||||
{ "K", SDL_SCANCODE_K },
|
||||
{ "L", SDL_SCANCODE_L },
|
||||
{ "M", SDL_SCANCODE_M },
|
||||
{ "N", SDL_SCANCODE_N },
|
||||
{ "O", SDL_SCANCODE_O },
|
||||
{ "P", SDL_SCANCODE_P },
|
||||
{ "Q", SDL_SCANCODE_Q },
|
||||
{ "R", SDL_SCANCODE_R },
|
||||
{ "S", SDL_SCANCODE_S },
|
||||
{ "T", SDL_SCANCODE_T },
|
||||
{ "U", SDL_SCANCODE_U },
|
||||
{ "V", SDL_SCANCODE_V },
|
||||
{ "W", SDL_SCANCODE_W },
|
||||
{ "X", SDL_SCANCODE_X },
|
||||
{ "Y", SDL_SCANCODE_Y },
|
||||
{ "Z", SDL_SCANCODE_Z },
|
||||
|
||||
{ "F1", SDL_SCANCODE_F1 },
|
||||
{ "F2", SDL_SCANCODE_F2 },
|
||||
{ "F3", SDL_SCANCODE_F3 },
|
||||
{ "F4", SDL_SCANCODE_F4 },
|
||||
{ "F5", SDL_SCANCODE_F5 },
|
||||
{ "F6", SDL_SCANCODE_F6 },
|
||||
{ "F7", SDL_SCANCODE_F7 },
|
||||
{ "F8", SDL_SCANCODE_F8 },
|
||||
{ "F9", SDL_SCANCODE_F9 },
|
||||
{ "F10", SDL_SCANCODE_F10 },
|
||||
{ "F11", SDL_SCANCODE_F11 },
|
||||
{ "F12", SDL_SCANCODE_F12 },
|
||||
{ "LeftArrow", SDL_SCANCODE_LEFT },
|
||||
{ "RightArrow", SDL_SCANCODE_RIGHT },
|
||||
{ "UpArrow", SDL_SCANCODE_UP },
|
||||
{ "DownArrow", SDL_SCANCODE_DOWN },
|
||||
|
||||
{ "A", SDL_SCANCODE_A },
|
||||
{ "B", SDL_SCANCODE_B },
|
||||
{ "C", SDL_SCANCODE_C },
|
||||
{ "D", SDL_SCANCODE_D },
|
||||
{ "E", SDL_SCANCODE_E },
|
||||
{ "F", SDL_SCANCODE_F },
|
||||
{ "G", SDL_SCANCODE_G },
|
||||
{ "H", SDL_SCANCODE_H },
|
||||
{ "I", SDL_SCANCODE_I },
|
||||
{ "J", SDL_SCANCODE_J },
|
||||
{ "K", SDL_SCANCODE_K },
|
||||
{ "L", SDL_SCANCODE_L },
|
||||
{ "M", SDL_SCANCODE_M },
|
||||
{ "N", SDL_SCANCODE_N },
|
||||
{ "O", SDL_SCANCODE_O },
|
||||
{ "P", SDL_SCANCODE_P },
|
||||
{ "Q", SDL_SCANCODE_Q },
|
||||
{ "R", SDL_SCANCODE_R },
|
||||
{ "S", SDL_SCANCODE_S },
|
||||
{ "T", SDL_SCANCODE_T },
|
||||
{ "U", SDL_SCANCODE_U },
|
||||
{ "V", SDL_SCANCODE_V },
|
||||
{ "W", SDL_SCANCODE_W },
|
||||
{ "X", SDL_SCANCODE_X },
|
||||
{ "Y", SDL_SCANCODE_Y },
|
||||
{ "Z", SDL_SCANCODE_Z },
|
||||
{ "LeftAlt", SDL_SCANCODE_LALT },
|
||||
{ "LeftCtrl", SDL_SCANCODE_LCTRL },
|
||||
{ "LeftBracket", SDL_SCANCODE_LEFTBRACKET },
|
||||
{ "LeftSuper", SDL_SCANCODE_LGUI },
|
||||
{ "LeftShift", SDL_SCANCODE_LSHIFT },
|
||||
{ "RightAlt", SDL_SCANCODE_RALT },
|
||||
{ "RightCtrl", SDL_SCANCODE_RCTRL },
|
||||
{ "RightSuper", SDL_SCANCODE_RGUI },
|
||||
{ "RightBracket", SDL_SCANCODE_RIGHTBRACKET },
|
||||
{ "RightShift", SDL_SCANCODE_RSHIFT },
|
||||
|
||||
{ "LeftArrow", SDL_SCANCODE_LEFT },
|
||||
{ "RightArrow", SDL_SCANCODE_RIGHT },
|
||||
{ "UpArrow", SDL_SCANCODE_UP },
|
||||
{ "DownArrow", SDL_SCANCODE_DOWN },
|
||||
{ "Apostrophe", SDL_SCANCODE_APOSTROPHE },
|
||||
{ "BackSlash", SDL_SCANCODE_BACKSLASH },
|
||||
{ "Backspace", SDL_SCANCODE_BACKSPACE },
|
||||
{ "CapsLock", SDL_SCANCODE_CAPSLOCK },
|
||||
{ "Comma", SDL_SCANCODE_COMMA },
|
||||
{ "Delete", SDL_SCANCODE_DELETE },
|
||||
{ "End", SDL_SCANCODE_END },
|
||||
{ "Enter", SDL_SCANCODE_RETURN },
|
||||
{ "Equals", SDL_SCANCODE_EQUALS },
|
||||
{ "Escape", SDL_SCANCODE_ESCAPE },
|
||||
{ "Home", SDL_SCANCODE_HOME },
|
||||
{ "Insert", SDL_SCANCODE_INSERT },
|
||||
{ "Minus", SDL_SCANCODE_MINUS },
|
||||
{ "NumLock", SDL_SCANCODE_NUMLOCKCLEAR },
|
||||
{ "PageDown", SDL_SCANCODE_PAGEDOWN },
|
||||
{ "PageUp", SDL_SCANCODE_PAGEUP },
|
||||
{ "Period", SDL_SCANCODE_PERIOD },
|
||||
{ "Pause", SDL_SCANCODE_PAUSE },
|
||||
{ "PrintScreen", SDL_SCANCODE_PRINTSCREEN },
|
||||
{ "ScrollLock", SDL_SCANCODE_SCROLLLOCK },
|
||||
{ "Semicolon", SDL_SCANCODE_SEMICOLON },
|
||||
{ "Slash", SDL_SCANCODE_SLASH },
|
||||
{ "Space", SDL_SCANCODE_SPACE },
|
||||
{ "Tab", SDL_SCANCODE_TAB },
|
||||
}));
|
||||
|
||||
{ "LeftAlt", SDL_SCANCODE_LALT },
|
||||
{ "LeftCtrl", SDL_SCANCODE_LCTRL },
|
||||
{ "LeftBracket", SDL_SCANCODE_LEFTBRACKET },
|
||||
{ "LeftSuper", SDL_SCANCODE_LGUI },
|
||||
{ "LeftShift", SDL_SCANCODE_LSHIFT },
|
||||
{ "RightAlt", SDL_SCANCODE_RALT },
|
||||
{ "RightCtrl", SDL_SCANCODE_RCTRL },
|
||||
{ "RightSuper", SDL_SCANCODE_RGUI },
|
||||
{ "RightBracket", SDL_SCANCODE_RIGHTBRACKET },
|
||||
{ "RightShift", SDL_SCANCODE_RSHIFT },
|
||||
|
||||
{ "Apostrophe", SDL_SCANCODE_APOSTROPHE },
|
||||
{ "BackSlash", SDL_SCANCODE_BACKSLASH },
|
||||
{ "Backspace", SDL_SCANCODE_BACKSPACE },
|
||||
{ "CapsLock", SDL_SCANCODE_CAPSLOCK },
|
||||
{ "Comma", SDL_SCANCODE_COMMA },
|
||||
{ "Delete", SDL_SCANCODE_DELETE },
|
||||
{ "End", SDL_SCANCODE_END },
|
||||
{ "Enter", SDL_SCANCODE_RETURN },
|
||||
{ "Equals", SDL_SCANCODE_EQUALS },
|
||||
{ "Escape", SDL_SCANCODE_ESCAPE },
|
||||
{ "Home", SDL_SCANCODE_HOME },
|
||||
{ "Insert", SDL_SCANCODE_INSERT },
|
||||
{ "Minus", SDL_SCANCODE_MINUS },
|
||||
{ "NumLock", SDL_SCANCODE_NUMLOCKCLEAR },
|
||||
{ "PageDown", SDL_SCANCODE_PAGEDOWN },
|
||||
{ "PageUp", SDL_SCANCODE_PAGEUP },
|
||||
{ "Period", SDL_SCANCODE_PERIOD },
|
||||
{ "Pause", SDL_SCANCODE_PAUSE },
|
||||
{ "PrintScreen", SDL_SCANCODE_PRINTSCREEN },
|
||||
{ "ScrollLock", SDL_SCANCODE_SCROLLLOCK },
|
||||
{ "Semicolon", SDL_SCANCODE_SEMICOLON },
|
||||
{ "Slash", SDL_SCANCODE_SLASH },
|
||||
{ "Space", SDL_SCANCODE_SPACE },
|
||||
{ "Tab", SDL_SCANCODE_TAB },
|
||||
}));
|
||||
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
lua["openmw_input"] = LuaUtil::makeReadOnly(api);
|
||||
return lua["openmw_input"];
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ namespace MWLua
|
||||
if (it != self->mStatsCache.end())
|
||||
return it->second;
|
||||
}
|
||||
return sol::make_object(context.mLua->sol(), getValue(context, prop, mObject.ptr()));
|
||||
return sol::make_object(context.mLua->unsafeState(), getValue(context, prop, mObject.ptr()));
|
||||
}
|
||||
|
||||
void set(const Context& context, std::string_view prop, const sol::object& value) const
|
||||
@ -82,9 +82,9 @@ namespace MWLua
|
||||
if (prop == "condition")
|
||||
{
|
||||
if (ptr.mRef->getType() == ESM::REC_LIGH)
|
||||
return sol::make_object(context.mLua->sol(), ptr.getClass().getRemainingUsageTime(ptr));
|
||||
return sol::make_object(context.mLua->unsafeState(), ptr.getClass().getRemainingUsageTime(ptr));
|
||||
else if (ptr.getClass().hasItemHealth(ptr))
|
||||
return sol::make_object(context.mLua->sol(),
|
||||
return sol::make_object(context.mLua->unsafeState(),
|
||||
ptr.getClass().getItemHealth(ptr) + ptr.getCellRef().getChargeIntRemainder());
|
||||
}
|
||||
else if (prop == "enchantmentCharge")
|
||||
@ -99,9 +99,10 @@ namespace MWLua
|
||||
const auto* enchantment = store->get<ESM::Enchantment>().find(enchantmentName);
|
||||
|
||||
if (charge == -1) // return the full charge
|
||||
return sol::make_object(context.mLua->sol(), MWMechanics::getEnchantmentCharge(*enchantment));
|
||||
return sol::make_object(
|
||||
context.mLua->unsafeState(), MWMechanics::getEnchantmentCharge(*enchantment));
|
||||
|
||||
return sol::make_object(context.mLua->sol(), charge);
|
||||
return sol::make_object(context.mLua->unsafeState(), charge);
|
||||
}
|
||||
else if (prop == "soul")
|
||||
{
|
||||
@ -109,7 +110,7 @@ namespace MWLua
|
||||
if (soul.empty())
|
||||
return sol::lua_nil;
|
||||
|
||||
return sol::make_object(context.mLua->sol(), soul.serializeText());
|
||||
return sol::make_object(context.mLua->unsafeState(), soul.serializeText());
|
||||
}
|
||||
|
||||
return sol::lua_nil;
|
||||
@ -185,7 +186,7 @@ namespace MWLua
|
||||
return {};
|
||||
};
|
||||
|
||||
sol::usertype<ItemData> itemData = context.mLua->sol().new_usertype<ItemData>("ItemData");
|
||||
sol::usertype<ItemData> itemData = context.sol().new_usertype<ItemData>("ItemData");
|
||||
itemData[sol::meta_function::new_index] = [](const ItemData& stat, const sol::variadic_args args) {
|
||||
throw std::runtime_error("Unknown ItemData property '" + args.get<std::string>() + "'");
|
||||
};
|
||||
|
@ -38,8 +38,9 @@ namespace MWLua
|
||||
|
||||
void LocalScripts::initializeSelfPackage(const Context& context)
|
||||
{
|
||||
auto lua = context.sol();
|
||||
using ActorControls = MWBase::LuaManager::ActorControls;
|
||||
sol::usertype<ActorControls> controls = context.mLua->sol().new_usertype<ActorControls>("ActorControls");
|
||||
sol::usertype<ActorControls> controls = lua.new_usertype<ActorControls>("ActorControls");
|
||||
|
||||
#define CONTROL(TYPE, FIELD) \
|
||||
sol::property([](const ActorControls& c) { return c.FIELD; }, \
|
||||
@ -57,8 +58,8 @@ namespace MWLua
|
||||
controls["use"] = CONTROL(int, mUse);
|
||||
#undef CONTROL
|
||||
|
||||
sol::usertype<SelfObject> selfAPI = context.mLua->sol().new_usertype<SelfObject>(
|
||||
"SelfObject", sol::base_classes, sol::bases<LObject, Object>());
|
||||
sol::usertype<SelfObject> selfAPI
|
||||
= lua.new_usertype<SelfObject>("SelfObject", sol::base_classes, sol::bases<LObject, Object>());
|
||||
selfAPI[sol::meta_function::to_string]
|
||||
= [](SelfObject& self) { return "openmw.self[" + self.toString() + "]"; };
|
||||
selfAPI["object"] = sol::readonly_property([](SelfObject& self) -> LObject { return LObject(self); });
|
||||
@ -66,13 +67,13 @@ namespace MWLua
|
||||
selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; };
|
||||
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; };
|
||||
selfAPI["ATTACK_TYPE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWMechanics::AttackType>(
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWMechanics::AttackType>(lua,
|
||||
{ { "NoAttack", MWMechanics::AttackType::NoAttack }, { "Any", MWMechanics::AttackType::Any },
|
||||
{ "Chop", MWMechanics::AttackType::Chop }, { "Slash", MWMechanics::AttackType::Slash },
|
||||
{ "Thrust", MWMechanics::AttackType::Thrust } }));
|
||||
|
||||
using AiPackage = MWMechanics::AiPackage;
|
||||
sol::usertype<AiPackage> aiPackage = context.mLua->sol().new_usertype<AiPackage>("AiPackage");
|
||||
sol::usertype<AiPackage> aiPackage = lua.new_usertype<AiPackage>("AiPackage");
|
||||
aiPackage["type"] = sol::readonly_property([](const AiPackage& p) -> std::string_view {
|
||||
switch (p.getTypeId())
|
||||
{
|
||||
@ -113,23 +114,24 @@ namespace MWLua
|
||||
aiPackage["destPosition"] = sol::readonly_property([](const AiPackage& p) { return p.getDestination(); });
|
||||
aiPackage["distance"] = sol::readonly_property([](const AiPackage& p) { return p.getDistance(); });
|
||||
aiPackage["duration"] = sol::readonly_property([](const AiPackage& p) { return p.getDuration(); });
|
||||
aiPackage["idle"] = sol::readonly_property([context](const AiPackage& p) -> sol::optional<sol::table> {
|
||||
if (p.getTypeId() == MWMechanics::AiPackageTypeId::Wander)
|
||||
{
|
||||
sol::table idles(context.mLua->sol(), sol::create);
|
||||
const std::vector<unsigned char>& idle = static_cast<const MWMechanics::AiWander&>(p).getIdle();
|
||||
if (!idle.empty())
|
||||
{
|
||||
for (size_t i = 0; i < idle.size(); ++i)
|
||||
{
|
||||
std::string_view groupName = MWMechanics::AiWander::getIdleGroupName(i);
|
||||
idles[groupName] = idle[i];
|
||||
}
|
||||
return idles;
|
||||
}
|
||||
}
|
||||
return sol::nullopt;
|
||||
});
|
||||
aiPackage["idle"]
|
||||
= sol::readonly_property([](sol::this_state lua, const AiPackage& p) -> sol::optional<sol::table> {
|
||||
if (p.getTypeId() == MWMechanics::AiPackageTypeId::Wander)
|
||||
{
|
||||
sol::table idles(lua, sol::create);
|
||||
const std::vector<unsigned char>& idle = static_cast<const MWMechanics::AiWander&>(p).getIdle();
|
||||
if (!idle.empty())
|
||||
{
|
||||
for (size_t i = 0; i < idle.size(); ++i)
|
||||
{
|
||||
std::string_view groupName = MWMechanics::AiWander::getIdleGroupName(i);
|
||||
idles[groupName] = idle[i];
|
||||
}
|
||||
return idles;
|
||||
}
|
||||
}
|
||||
return sol::nullopt;
|
||||
});
|
||||
|
||||
aiPackage["isRepeat"] = sol::readonly_property([](const AiPackage& p) { return p.getRepeat(); });
|
||||
|
||||
@ -226,7 +228,8 @@ namespace MWLua
|
||||
: LuaUtil::ScriptsContainer(lua, "L" + obj.id().toString())
|
||||
, mData(obj)
|
||||
{
|
||||
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
|
||||
lua->protectedCall(
|
||||
[&](LuaUtil::LuaView& view) { addPackage("openmw.self", sol::make_object(view.sol(), &mData)); });
|
||||
registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers,
|
||||
&mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers, &mOnSkillUse,
|
||||
&mOnSkillLevelUp });
|
||||
|
@ -29,7 +29,7 @@ namespace MWLua
|
||||
{
|
||||
std::map<std::string, sol::object> initCommonPackages(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.mLua->sol();
|
||||
sol::state_view lua = context.mLua->unsafeState();
|
||||
MWWorld::DateTimeManager* tm = MWBase::Environment::get().getWorld()->getTimeManager();
|
||||
return {
|
||||
{ "openmw.animation", initAnimationPackage(context) },
|
||||
@ -69,7 +69,7 @@ namespace MWLua
|
||||
{
|
||||
return {
|
||||
{ "openmw.ambient", initAmbientPackage(context) },
|
||||
{ "openmw.camera", initCameraPackage(context.mLua->sol()) },
|
||||
{ "openmw.camera", initCameraPackage(context.sol()) },
|
||||
{ "openmw.debug", initDebugPackage(context) },
|
||||
{ "openmw.input", initInputPackage(context) },
|
||||
{ "openmw.postprocessing", initPostprocessingPackage(context) },
|
||||
|
@ -83,47 +83,49 @@ namespace MWLua
|
||||
|
||||
void LuaManager::init()
|
||||
{
|
||||
Context globalContext;
|
||||
globalContext.mType = Context::Global;
|
||||
globalContext.mLuaManager = this;
|
||||
globalContext.mLua = &mLua;
|
||||
globalContext.mObjectLists = &mObjectLists;
|
||||
globalContext.mLuaEvents = &mLuaEvents;
|
||||
globalContext.mSerializer = mGlobalSerializer.get();
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
Context globalContext;
|
||||
globalContext.mType = Context::Global;
|
||||
globalContext.mLuaManager = this;
|
||||
globalContext.mLua = &mLua;
|
||||
globalContext.mObjectLists = &mObjectLists;
|
||||
globalContext.mLuaEvents = &mLuaEvents;
|
||||
globalContext.mSerializer = mGlobalSerializer.get();
|
||||
|
||||
Context localContext = globalContext;
|
||||
localContext.mType = Context::Local;
|
||||
localContext.mSerializer = mLocalSerializer.get();
|
||||
Context localContext = globalContext;
|
||||
localContext.mType = Context::Local;
|
||||
localContext.mSerializer = mLocalSerializer.get();
|
||||
|
||||
Context menuContext = globalContext;
|
||||
menuContext.mType = Context::Menu;
|
||||
Context menuContext = globalContext;
|
||||
menuContext.mType = Context::Menu;
|
||||
|
||||
for (const auto& [name, package] : initCommonPackages(globalContext))
|
||||
mLua.addCommonPackage(name, package);
|
||||
for (const auto& [name, package] : initGlobalPackages(globalContext))
|
||||
mGlobalScripts.addPackage(name, package);
|
||||
for (const auto& [name, package] : initMenuPackages(menuContext))
|
||||
mMenuScripts.addPackage(name, package);
|
||||
for (const auto& [name, package] : initCommonPackages(globalContext))
|
||||
mLua.addCommonPackage(name, package);
|
||||
for (const auto& [name, package] : initGlobalPackages(globalContext))
|
||||
mGlobalScripts.addPackage(name, package);
|
||||
for (const auto& [name, package] : initMenuPackages(menuContext))
|
||||
mMenuScripts.addPackage(name, package);
|
||||
|
||||
mLocalPackages = initLocalPackages(localContext);
|
||||
mLocalPackages = initLocalPackages(localContext);
|
||||
|
||||
mPlayerPackages = initPlayerPackages(localContext);
|
||||
mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
|
||||
mPlayerPackages = initPlayerPackages(localContext);
|
||||
mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
|
||||
|
||||
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
|
||||
mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua, &mGlobalStorage));
|
||||
mMenuScripts.addPackage(
|
||||
"openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua, &mGlobalStorage, &mPlayerStorage));
|
||||
mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua, &mGlobalStorage);
|
||||
mPlayerPackages["openmw.storage"]
|
||||
= LuaUtil::LuaStorage::initPlayerPackage(mLua, &mGlobalStorage, &mPlayerStorage);
|
||||
LuaUtil::LuaStorage::initLuaBindings(view);
|
||||
mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(view, &mGlobalStorage));
|
||||
mMenuScripts.addPackage(
|
||||
"openmw.storage", LuaUtil::LuaStorage::initMenuPackage(view, &mGlobalStorage, &mPlayerStorage));
|
||||
mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(view, &mGlobalStorage);
|
||||
mPlayerPackages["openmw.storage"]
|
||||
= LuaUtil::LuaStorage::initPlayerPackage(view, &mGlobalStorage, &mPlayerStorage);
|
||||
|
||||
mPlayerStorage.setActive(true);
|
||||
mGlobalStorage.setActive(false);
|
||||
mPlayerStorage.setActive(true);
|
||||
mGlobalStorage.setActive(false);
|
||||
|
||||
initConfiguration();
|
||||
mInitialized = true;
|
||||
mMenuScripts.addAutoStartedScripts();
|
||||
initConfiguration();
|
||||
mInitialized = true;
|
||||
mMenuScripts.addAutoStartedScripts();
|
||||
});
|
||||
}
|
||||
|
||||
void LuaManager::loadPermanentStorage(const std::filesystem::path& userConfigPath)
|
||||
@ -132,23 +134,28 @@ namespace MWLua
|
||||
mGlobalStorage.setActive(true);
|
||||
const auto globalPath = userConfigPath / "global_storage.bin";
|
||||
const auto playerPath = userConfigPath / "player_storage.bin";
|
||||
if (std::filesystem::exists(globalPath))
|
||||
mGlobalStorage.load(globalPath);
|
||||
if (std::filesystem::exists(playerPath))
|
||||
mPlayerStorage.load(playerPath);
|
||||
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
if (std::filesystem::exists(globalPath))
|
||||
mGlobalStorage.load(view.sol(), globalPath);
|
||||
if (std::filesystem::exists(playerPath))
|
||||
mPlayerStorage.load(view.sol(), playerPath);
|
||||
});
|
||||
}
|
||||
|
||||
void LuaManager::savePermanentStorage(const std::filesystem::path& userConfigPath)
|
||||
{
|
||||
if (mGlobalScriptsStarted)
|
||||
mGlobalStorage.save(userConfigPath / "global_storage.bin");
|
||||
mPlayerStorage.save(userConfigPath / "player_storage.bin");
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
if (mGlobalScriptsStarted)
|
||||
mGlobalStorage.save(view.sol(), userConfigPath / "global_storage.bin");
|
||||
mPlayerStorage.save(view.sol(), userConfigPath / "player_storage.bin");
|
||||
});
|
||||
}
|
||||
|
||||
void LuaManager::update()
|
||||
{
|
||||
if (const int steps = Settings::lua().mGcStepsPerFrame; steps > 0)
|
||||
lua_gc(mLua.sol(), LUA_GCSTEP, steps);
|
||||
lua_gc(mLua.unsafeState(), LUA_GCSTEP, steps);
|
||||
|
||||
if (mPlayer.isEmpty())
|
||||
return; // The game is not started yet.
|
||||
@ -330,7 +337,7 @@ namespace MWLua
|
||||
mInputActions.clear();
|
||||
mInputTriggers.clear();
|
||||
for (int i = 0; i < 5; ++i)
|
||||
lua_gc(mLua.sol(), LUA_GCCOLLECT, 0);
|
||||
lua_gc(mLua.unsafeState(), LUA_GCCOLLECT, 0);
|
||||
}
|
||||
|
||||
void LuaManager::setupPlayer(const MWWorld::Ptr& ptr)
|
||||
@ -424,35 +431,37 @@ namespace MWLua
|
||||
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
|
||||
std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback)
|
||||
{
|
||||
sol::table options = mLua.newTable();
|
||||
options["blendMask"] = blendMask;
|
||||
options["autoDisable"] = autodisable;
|
||||
options["speed"] = speedmult;
|
||||
options["startKey"] = start;
|
||||
options["stopKey"] = stop;
|
||||
options["startPoint"] = startpoint;
|
||||
options["loops"] = loops;
|
||||
options["forceLoop"] = loopfallback;
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
sol::table options = view.newTable();
|
||||
options["blendMask"] = blendMask;
|
||||
options["autoDisable"] = autodisable;
|
||||
options["speed"] = speedmult;
|
||||
options["startKey"] = start;
|
||||
options["stopKey"] = stop;
|
||||
options["startPoint"] = startpoint;
|
||||
options["loops"] = loops;
|
||||
options["forceLoop"] = loopfallback;
|
||||
|
||||
bool priorityAsTable = false;
|
||||
for (uint32_t i = 1; i < MWRender::sNumBlendMasks; i++)
|
||||
if (priority[static_cast<MWRender::BoneGroup>(i)] != priority[static_cast<MWRender::BoneGroup>(0)])
|
||||
priorityAsTable = true;
|
||||
if (priorityAsTable)
|
||||
{
|
||||
sol::table priorityTable = mLua.newTable();
|
||||
for (uint32_t i = 0; i < MWRender::sNumBlendMasks; i++)
|
||||
priorityTable[static_cast<MWRender::BoneGroup>(i)] = priority[static_cast<MWRender::BoneGroup>(i)];
|
||||
options["priority"] = priorityTable;
|
||||
}
|
||||
else
|
||||
options["priority"] = priority[MWRender::BoneGroup_LowerBody];
|
||||
bool priorityAsTable = false;
|
||||
for (uint32_t i = 1; i < MWRender::sNumBlendMasks; i++)
|
||||
if (priority[static_cast<MWRender::BoneGroup>(i)] != priority[static_cast<MWRender::BoneGroup>(0)])
|
||||
priorityAsTable = true;
|
||||
if (priorityAsTable)
|
||||
{
|
||||
sol::table priorityTable = view.newTable();
|
||||
for (uint32_t i = 0; i < MWRender::sNumBlendMasks; i++)
|
||||
priorityTable[static_cast<MWRender::BoneGroup>(i)] = priority[static_cast<MWRender::BoneGroup>(i)];
|
||||
options["priority"] = priorityTable;
|
||||
}
|
||||
else
|
||||
options["priority"] = priority[MWRender::BoneGroup_LowerBody];
|
||||
|
||||
// mEngineEvents.addToQueue(event);
|
||||
// Has to be called immediately, otherwise engine details that depend on animations playing immediately
|
||||
// break.
|
||||
if (auto* scripts = actor.getRefData().getLuaScripts())
|
||||
scripts->onPlayAnimation(groupname, options);
|
||||
// mEngineEvents.addToQueue(event);
|
||||
// Has to be called immediately, otherwise engine details that depend on animations playing immediately
|
||||
// break.
|
||||
if (auto* scripts = actor.getRefData().getLuaScripts())
|
||||
scripts->onPlayAnimation(groupname, options);
|
||||
});
|
||||
}
|
||||
|
||||
void LuaManager::skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale)
|
||||
@ -593,7 +602,9 @@ namespace MWLua
|
||||
|
||||
ESM::LuaScripts globalScripts;
|
||||
globalScripts.load(reader);
|
||||
mLuaEvents.load(mLua.sol(), reader, mContentFileMapping, mGlobalLoader.get());
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
mLuaEvents.load(view.sol(), reader, mContentFileMapping, mGlobalLoader.get());
|
||||
});
|
||||
|
||||
mGlobalScripts.setSavedDataDeserializer(mGlobalLoader.get());
|
||||
mGlobalScripts.load(globalScripts);
|
||||
@ -696,7 +707,9 @@ namespace MWLua
|
||||
{
|
||||
sol::object selected = sol::nil;
|
||||
if (!selectedPtr.isEmpty())
|
||||
selected = sol::make_object(mLua.sol(), LObject(getId(selectedPtr)));
|
||||
mLua.protectedCall([&](LuaUtil::LuaView& view) {
|
||||
selected = sol::make_object(view.sol(), LObject(getId(selectedPtr)));
|
||||
});
|
||||
if (playerScripts->consoleCommand(consoleMode, command, selected))
|
||||
processed = true;
|
||||
}
|
||||
|
@ -150,8 +150,9 @@ namespace MWLua
|
||||
template <class Arg>
|
||||
std::function<void(Arg)> wrapLuaCallback(const LuaUtil::Callback& c)
|
||||
{
|
||||
return
|
||||
[this, c](Arg arg) { this->queueCallback(c, sol::main_object(this->mLua.sol(), sol::in_place, arg)); };
|
||||
return [this, c](Arg arg) {
|
||||
this->queueCallback(c, sol::main_object(this->mLua.unsafeState(), sol::in_place, arg));
|
||||
};
|
||||
}
|
||||
|
||||
LuaUi::ResourceManager* uiResourceManager() { return &mUiResourceManager; }
|
||||
@ -227,8 +228,8 @@ namespace MWLua
|
||||
std::vector<std::pair<std::string, Misc::Color>> mInGameConsoleMessages;
|
||||
std::optional<ObjectId> mDelayedUiModeChangedArg;
|
||||
|
||||
LuaUtil::LuaStorage mGlobalStorage{ mLua.sol() };
|
||||
LuaUtil::LuaStorage mPlayerStorage{ mLua.sol() };
|
||||
LuaUtil::LuaStorage mGlobalStorage;
|
||||
LuaUtil::LuaStorage mPlayerStorage;
|
||||
|
||||
LuaUtil::InputAction::Registry mInputActions;
|
||||
LuaUtil::InputTrigger::Registry mInputTriggers;
|
||||
|
@ -214,33 +214,36 @@ namespace MWLua
|
||||
|
||||
sol::table initCoreMagicBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table magicApi(lua, sol::create);
|
||||
|
||||
// Constants
|
||||
magicApi["RANGE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, ESM::RangeType>({
|
||||
{ "Self", ESM::RT_Self },
|
||||
{ "Touch", ESM::RT_Touch },
|
||||
{ "Target", ESM::RT_Target },
|
||||
}));
|
||||
magicApi["RANGE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, ESM::RangeType>(lua,
|
||||
{
|
||||
{ "Self", ESM::RT_Self },
|
||||
{ "Touch", ESM::RT_Touch },
|
||||
{ "Target", ESM::RT_Target },
|
||||
}));
|
||||
magicApi["SPELL_TYPE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, ESM::Spell::SpellType>({
|
||||
{ "Spell", ESM::Spell::ST_Spell },
|
||||
{ "Ability", ESM::Spell::ST_Ability },
|
||||
{ "Blight", ESM::Spell::ST_Blight },
|
||||
{ "Disease", ESM::Spell::ST_Disease },
|
||||
{ "Curse", ESM::Spell::ST_Curse },
|
||||
{ "Power", ESM::Spell::ST_Power },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, ESM::Spell::SpellType>(lua,
|
||||
{
|
||||
{ "Spell", ESM::Spell::ST_Spell },
|
||||
{ "Ability", ESM::Spell::ST_Ability },
|
||||
{ "Blight", ESM::Spell::ST_Blight },
|
||||
{ "Disease", ESM::Spell::ST_Disease },
|
||||
{ "Curse", ESM::Spell::ST_Curse },
|
||||
{ "Power", ESM::Spell::ST_Power },
|
||||
}));
|
||||
magicApi["ENCHANTMENT_TYPE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, ESM::Enchantment::Type>({
|
||||
{ "CastOnce", ESM::Enchantment::Type::CastOnce },
|
||||
{ "CastOnStrike", ESM::Enchantment::Type::WhenStrikes },
|
||||
{ "CastOnUse", ESM::Enchantment::Type::WhenUsed },
|
||||
{ "ConstantEffect", ESM::Enchantment::Type::ConstantEffect },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, ESM::Enchantment::Type>(lua,
|
||||
{
|
||||
{ "CastOnce", ESM::Enchantment::Type::CastOnce },
|
||||
{ "CastOnStrike", ESM::Enchantment::Type::WhenStrikes },
|
||||
{ "CastOnUse", ESM::Enchantment::Type::WhenUsed },
|
||||
{ "ConstantEffect", ESM::Enchantment::Type::ConstantEffect },
|
||||
}));
|
||||
|
||||
sol::table effect(context.mLua->sol(), sol::create);
|
||||
sol::table effect(lua, sol::create);
|
||||
magicApi["EFFECT_TYPE"] = LuaUtil::makeStrictReadOnly(effect);
|
||||
for (const auto& name : ESM::MagicEffect::sIndexNames)
|
||||
{
|
||||
@ -369,7 +372,7 @@ namespace MWLua
|
||||
= sol::readonly_property([](const ESM::IndexedENAMstruct& params) -> int { return params.mIndex; });
|
||||
|
||||
// MagicEffect record
|
||||
auto magicEffectT = context.mLua->sol().new_usertype<ESM::MagicEffect>("ESM3_MagicEffect");
|
||||
auto magicEffectT = lua.new_usertype<ESM::MagicEffect>("ESM3_MagicEffect");
|
||||
|
||||
magicEffectT[sol::meta_function::to_string] = [](const ESM::MagicEffect& rec) {
|
||||
return "ESM3_MagicEffect[" + ESM::MagicEffect::indexToGmstString(rec.mIndex) + "]";
|
||||
@ -437,7 +440,7 @@ namespace MWLua
|
||||
// magicEffectT["projectileSpeed"]
|
||||
// = sol::readonly_property([](const ESM::MagicEffect& rec) -> float { return rec.mData.mSpeed; });
|
||||
|
||||
auto activeSpellEffectT = context.mLua->sol().new_usertype<ESM::ActiveEffect>("ActiveSpellEffect");
|
||||
auto activeSpellEffectT = lua.new_usertype<ESM::ActiveEffect>("ActiveSpellEffect");
|
||||
activeSpellEffectT[sol::meta_function::to_string] = [](const ESM::ActiveEffect& effect) {
|
||||
return "ActiveSpellEffect[" + ESM::MagicEffect::indexToGmstString(effect.mEffectId) + "]";
|
||||
};
|
||||
@ -508,7 +511,7 @@ namespace MWLua
|
||||
return effect.mDuration;
|
||||
});
|
||||
|
||||
auto activeSpellT = context.mLua->sol().new_usertype<ActiveSpell>("ActiveSpellParams");
|
||||
auto activeSpellT = lua.new_usertype<ActiveSpell>("ActiveSpellParams");
|
||||
activeSpellT[sol::meta_function::to_string] = [](const ActiveSpell& activeSpell) {
|
||||
return "ActiveSpellParams[" + activeSpell.mParams.getSourceSpellId().serializeText() + "]";
|
||||
};
|
||||
@ -569,7 +572,7 @@ namespace MWLua
|
||||
return activeSpell.mParams.getActiveSpellId().serializeText();
|
||||
});
|
||||
|
||||
auto activeEffectT = context.mLua->sol().new_usertype<ActiveEffect>("ActiveEffect");
|
||||
auto activeEffectT = lua.new_usertype<ActiveEffect>("ActiveEffect");
|
||||
|
||||
activeEffectT[sol::meta_function::to_string] = [](const ActiveEffect& effect) {
|
||||
return "ActiveEffect[" + ESM::MagicEffect::indexToGmstString(effect.key.mId) + "]";
|
||||
@ -680,23 +683,24 @@ namespace MWLua
|
||||
|
||||
void addActorMagicBindings(sol::table& actor, const Context& context)
|
||||
{
|
||||
auto lua = context.sol();
|
||||
const MWWorld::Store<ESM::Spell>* spellStore
|
||||
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||
|
||||
// types.Actor.spells(o)
|
||||
actor["spells"] = [](const sol::object& actor) { return ActorSpells{ actor }; };
|
||||
auto spellsT = context.mLua->sol().new_usertype<ActorSpells>("ActorSpells");
|
||||
auto spellsT = lua.new_usertype<ActorSpells>("ActorSpells");
|
||||
spellsT[sol::meta_function::to_string]
|
||||
= [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString() + "]"; };
|
||||
|
||||
actor["activeSpells"] = [](const sol::object& actor) { return ActorActiveSpells{ actor }; };
|
||||
auto activeSpellsT = context.mLua->sol().new_usertype<ActorActiveSpells>("ActorActiveSpells");
|
||||
auto activeSpellsT = lua.new_usertype<ActorActiveSpells>("ActorActiveSpells");
|
||||
activeSpellsT[sol::meta_function::to_string] = [](const ActorActiveSpells& spells) {
|
||||
return "ActorActiveSpells[" + spells.mActor.object().toString() + "]";
|
||||
};
|
||||
|
||||
actor["activeEffects"] = [](const sol::object& actor) { return ActorActiveEffects{ actor }; };
|
||||
auto activeEffectsT = context.mLua->sol().new_usertype<ActorActiveEffects>("ActorActiveEffects");
|
||||
auto activeEffectsT = lua.new_usertype<ActorActiveEffects>("ActorActiveEffects");
|
||||
activeEffectsT[sol::meta_function::to_string] = [](const ActorActiveEffects& effects) {
|
||||
return "ActorActiveEffects[" + effects.mActor.object().toString() + "]";
|
||||
};
|
||||
@ -798,10 +802,10 @@ namespace MWLua
|
||||
});
|
||||
|
||||
// pairs(types.Actor.spells(o))
|
||||
spellsT[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||
spellsT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
|
||||
|
||||
// ipairs(types.Actor.spells(o))
|
||||
spellsT[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||
spellsT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
|
||||
|
||||
// types.Actor.spells(o):add(id)
|
||||
spellsT["add"] = [context](const ActorSpells& spells, const sol::object& spellOrId) {
|
||||
|
@ -14,17 +14,17 @@ namespace MWLua
|
||||
{
|
||||
sol::table initMarkupPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
api["loadYaml"] = [lua = context.mLua, vfs](std::string_view fileName) {
|
||||
api["loadYaml"] = [lua, vfs](std::string_view fileName) {
|
||||
Files::IStreamPtr file = vfs->get(VFS::Path::Normalized(fileName));
|
||||
return LuaUtil::loadYaml(*file, lua->sol());
|
||||
};
|
||||
api["decodeYaml"] = [lua = context.mLua](std::string_view inputData) {
|
||||
return LuaUtil::loadYaml(std::string(inputData), lua->sol());
|
||||
return LuaUtil::loadYaml(*file, lua);
|
||||
};
|
||||
api["decodeYaml"]
|
||||
= [lua](std::string_view inputData) { return LuaUtil::loadYaml(std::string(inputData), lua); };
|
||||
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
}
|
||||
|
@ -30,15 +30,16 @@ namespace MWLua
|
||||
|
||||
sol::table initMenuPackage(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
api["STATE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWBase::StateManager::State>({
|
||||
{ "NoGame", MWBase::StateManager::State_NoGame },
|
||||
{ "Running", MWBase::StateManager::State_Running },
|
||||
{ "Ended", MWBase::StateManager::State_Ended },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWBase::StateManager::State>(lua,
|
||||
{
|
||||
{ "NoGame", MWBase::StateManager::State_NoGame },
|
||||
{ "Running", MWBase::StateManager::State_Running },
|
||||
{ "Ended", MWBase::StateManager::State_Ended },
|
||||
}));
|
||||
|
||||
api["getState"] = []() -> int { return MWBase::Environment::get().getStateManager()->getState(); };
|
||||
|
||||
|
@ -95,7 +95,8 @@ namespace MWLua
|
||||
|
||||
sol::table initMWScriptBindings(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
api["getGlobalScript"]
|
||||
= [](std::string_view recordId, sol::optional<GObject> player) -> sol::optional<MWScriptRef> {
|
||||
@ -121,10 +122,8 @@ namespace MWLua
|
||||
// api["getGlobalScripts"] = [](std::string_view recordId) -> list of scripts
|
||||
// api["getLocalScripts"] = [](const GObject& obj) -> list of scripts
|
||||
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::usertype<MWScriptRef> mwscript = context.mLua->sol().new_usertype<MWScriptRef>("MWScript");
|
||||
sol::usertype<MWScriptVariables> mwscriptVars
|
||||
= context.mLua->sol().new_usertype<MWScriptVariables>("MWScriptVariables");
|
||||
sol::usertype<MWScriptRef> mwscript = lua.new_usertype<MWScriptRef>("MWScript");
|
||||
sol::usertype<MWScriptVariables> mwscriptVars = lua.new_usertype<MWScriptVariables>("MWScriptVariables");
|
||||
mwscript[sol::meta_function::to_string]
|
||||
= [](const MWScriptRef& s) { return std::string("MWScript{") + s.mId.toDebugString() + "}"; };
|
||||
mwscript["isRunning"] = sol::readonly_property([](const MWScriptRef& s) { return s.isRunning(); });
|
||||
|
@ -53,11 +53,12 @@ namespace MWLua
|
||||
{
|
||||
sol::table initNearbyPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
ObjectLists* objectLists = context.mObjectLists;
|
||||
|
||||
sol::usertype<MWPhysics::RayCastingResult> rayResult
|
||||
= context.mLua->sol().new_usertype<MWPhysics::RayCastingResult>("RayCastingResult");
|
||||
= lua.new_usertype<MWPhysics::RayCastingResult>("RayCastingResult");
|
||||
rayResult["hit"] = sol::readonly_property([](const MWPhysics::RayCastingResult& r) { return r.mHit; });
|
||||
rayResult["hitPos"]
|
||||
= sol::readonly_property([](const MWPhysics::RayCastingResult& r) -> sol::optional<osg::Vec3f> {
|
||||
@ -82,18 +83,19 @@ namespace MWLua
|
||||
});
|
||||
|
||||
api["COLLISION_TYPE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWPhysics::CollisionType>({
|
||||
{ "World", MWPhysics::CollisionType_World },
|
||||
{ "Door", MWPhysics::CollisionType_Door },
|
||||
{ "Actor", MWPhysics::CollisionType_Actor },
|
||||
{ "HeightMap", MWPhysics::CollisionType_HeightMap },
|
||||
{ "Projectile", MWPhysics::CollisionType_Projectile },
|
||||
{ "Water", MWPhysics::CollisionType_Water },
|
||||
{ "Default", MWPhysics::CollisionType_Default },
|
||||
{ "AnyPhysical", MWPhysics::CollisionType_AnyPhysical },
|
||||
{ "Camera", MWPhysics::CollisionType_CameraOnly },
|
||||
{ "VisualOnly", MWPhysics::CollisionType_VisualOnly },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWPhysics::CollisionType>(lua,
|
||||
{
|
||||
{ "World", MWPhysics::CollisionType_World },
|
||||
{ "Door", MWPhysics::CollisionType_Door },
|
||||
{ "Actor", MWPhysics::CollisionType_Actor },
|
||||
{ "HeightMap", MWPhysics::CollisionType_HeightMap },
|
||||
{ "Projectile", MWPhysics::CollisionType_Projectile },
|
||||
{ "Water", MWPhysics::CollisionType_Water },
|
||||
{ "Default", MWPhysics::CollisionType_Default },
|
||||
{ "AnyPhysical", MWPhysics::CollisionType_AnyPhysical },
|
||||
{ "Camera", MWPhysics::CollisionType_CameraOnly },
|
||||
{ "VisualOnly", MWPhysics::CollisionType_VisualOnly },
|
||||
}));
|
||||
|
||||
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options) {
|
||||
std::vector<MWWorld::ConstPtr> ignore;
|
||||
@ -163,12 +165,13 @@ namespace MWLua
|
||||
ignore = parseIgnoreList(*options);
|
||||
}
|
||||
|
||||
context.mLuaManager->addAction([context, ignore = std::move(ignore),
|
||||
callback = LuaUtil::Callback::fromLua(callback), from, to] {
|
||||
MWPhysics::RayCastingResult res;
|
||||
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore);
|
||||
context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res));
|
||||
});
|
||||
context.mLuaManager->addAction(
|
||||
[context, ignore = std::move(ignore), callback = LuaUtil::Callback::fromLua(callback), from, to] {
|
||||
MWPhysics::RayCastingResult res;
|
||||
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore);
|
||||
context.mLuaManager->queueCallback(
|
||||
callback, sol::main_object(context.mLua->unsafeState(), sol::in_place, res));
|
||||
});
|
||||
};
|
||||
|
||||
api["getObjectByFormId"] = [](std::string_view formIdStr) -> LObject {
|
||||
@ -186,32 +189,35 @@ namespace MWLua
|
||||
api["players"] = LObjectList{ objectLists->getPlayers() };
|
||||
|
||||
api["NAVIGATOR_FLAGS"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, DetourNavigator::Flag>({
|
||||
{ "Walk", DetourNavigator::Flag_walk },
|
||||
{ "Swim", DetourNavigator::Flag_swim },
|
||||
{ "OpenDoor", DetourNavigator::Flag_openDoor },
|
||||
{ "UsePathgrid", DetourNavigator::Flag_usePathgrid },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, DetourNavigator::Flag>(lua,
|
||||
{
|
||||
{ "Walk", DetourNavigator::Flag_walk },
|
||||
{ "Swim", DetourNavigator::Flag_swim },
|
||||
{ "OpenDoor", DetourNavigator::Flag_openDoor },
|
||||
{ "UsePathgrid", DetourNavigator::Flag_usePathgrid },
|
||||
}));
|
||||
|
||||
api["COLLISION_SHAPE_TYPE"] = LuaUtil::makeStrictReadOnly(
|
||||
context.mLua->tableFromPairs<std::string_view, DetourNavigator::CollisionShapeType>({
|
||||
{ "Aabb", DetourNavigator::CollisionShapeType::Aabb },
|
||||
{ "RotatingBox", DetourNavigator::CollisionShapeType::RotatingBox },
|
||||
{ "Cylinder", DetourNavigator::CollisionShapeType::Cylinder },
|
||||
}));
|
||||
LuaUtil::tableFromPairs<std::string_view, DetourNavigator::CollisionShapeType>(lua,
|
||||
{
|
||||
{ "Aabb", DetourNavigator::CollisionShapeType::Aabb },
|
||||
{ "RotatingBox", DetourNavigator::CollisionShapeType::RotatingBox },
|
||||
{ "Cylinder", DetourNavigator::CollisionShapeType::Cylinder },
|
||||
}));
|
||||
|
||||
api["FIND_PATH_STATUS"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, DetourNavigator::Status>({
|
||||
{ "Success", DetourNavigator::Status::Success },
|
||||
{ "PartialPath", DetourNavigator::Status::PartialPath },
|
||||
{ "NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound },
|
||||
{ "StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound },
|
||||
{ "EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound },
|
||||
{ "MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed },
|
||||
{ "FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed },
|
||||
{ "InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed },
|
||||
{ "FindStraightPathFailed", DetourNavigator::Status::FindStraightPathFailed },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, DetourNavigator::Status>(lua,
|
||||
{
|
||||
{ "Success", DetourNavigator::Status::Success },
|
||||
{ "PartialPath", DetourNavigator::Status::PartialPath },
|
||||
{ "NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound },
|
||||
{ "StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound },
|
||||
{ "EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound },
|
||||
{ "MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed },
|
||||
{ "FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed },
|
||||
{ "InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed },
|
||||
{ "FindStraightPathFailed", DetourNavigator::Status::FindStraightPathFailed },
|
||||
}));
|
||||
|
||||
static const DetourNavigator::AgentBounds defaultAgentBounds{
|
||||
Settings::game().mActorCollisionShapeType,
|
||||
|
@ -164,7 +164,7 @@ namespace MWLua
|
||||
void registerObjectList(const std::string& prefix, const Context& context)
|
||||
{
|
||||
using ListT = ObjectList<ObjectT>;
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::usertype<ListT> listT = lua.new_usertype<ListT>(prefix + "ObjectList");
|
||||
listT[sol::meta_function::to_string]
|
||||
= [](const ListT& list) { return "{" + std::to_string(list.mIds->size()) + " objects}"; };
|
||||
@ -205,7 +205,7 @@ namespace MWLua
|
||||
void addOwnerbindings(sol::usertype<ObjectT>& objectT, const std::string& prefix, const Context& context)
|
||||
{
|
||||
using OwnerT = Owner<ObjectT>;
|
||||
sol::usertype<OwnerT> ownerT = context.mLua->sol().new_usertype<OwnerT>(prefix + "Owner");
|
||||
sol::usertype<OwnerT> ownerT = context.sol().new_usertype<OwnerT>(prefix + "Owner");
|
||||
|
||||
ownerT[sol::meta_function::to_string] = [](const OwnerT& o) { return "Owner[" + o.mObj.toString() + "]"; };
|
||||
|
||||
@ -329,9 +329,10 @@ namespace MWLua
|
||||
return LuaUtil::Box{ bb.center(), bb._max - bb.center() };
|
||||
};
|
||||
|
||||
objectT["type"] = sol::readonly_property(
|
||||
[types = getTypeToPackageTable(context.mLua->sol())](
|
||||
const ObjectT& o) mutable { return types[getLiveCellRefType(o.ptr().mRef)]; });
|
||||
objectT["type"]
|
||||
= sol::readonly_property([types = getTypeToPackageTable(context.sol())](const ObjectT& o) mutable {
|
||||
return types[getLiveCellRefType(o.ptr().mRef)];
|
||||
});
|
||||
|
||||
objectT["count"] = sol::readonly_property([](const ObjectT& o) { return o.ptr().getCellRef().getCount(); });
|
||||
objectT[sol::meta_function::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); };
|
||||
@ -553,12 +554,12 @@ namespace MWLua
|
||||
void addInventoryBindings(sol::usertype<ObjectT>& objectT, const std::string& prefix, const Context& context)
|
||||
{
|
||||
using InventoryT = Inventory<ObjectT>;
|
||||
sol::usertype<InventoryT> inventoryT = context.mLua->sol().new_usertype<InventoryT>(prefix + "Inventory");
|
||||
sol::usertype<InventoryT> inventoryT = context.sol().new_usertype<InventoryT>(prefix + "Inventory");
|
||||
|
||||
inventoryT[sol::meta_function::to_string]
|
||||
= [](const InventoryT& inv) { return "Inventory[" + inv.mObj.toString() + "]"; };
|
||||
|
||||
inventoryT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
|
||||
inventoryT["getAll"] = [ids = getPackageToTypeTable(context.mLua->unsafeState())](
|
||||
const InventoryT& inventory, sol::optional<sol::table> type) {
|
||||
int mask = -1;
|
||||
sol::optional<uint32_t> typeId = sol::nullopt;
|
||||
@ -681,7 +682,7 @@ namespace MWLua
|
||||
void initObjectBindings(const std::string& prefix, const Context& context)
|
||||
{
|
||||
sol::usertype<ObjectT> objectT
|
||||
= context.mLua->sol().new_usertype<ObjectT>(prefix + "Object", sol::base_classes, sol::bases<Object>());
|
||||
= context.sol().new_usertype<ObjectT>(prefix + "Object", sol::base_classes, sol::bases<Object>());
|
||||
addBasicBindings<ObjectT>(objectT, context);
|
||||
addInventoryBindings<ObjectT>(objectT, prefix, context);
|
||||
addOwnerbindings<ObjectT>(objectT, prefix, context);
|
||||
|
@ -96,9 +96,10 @@ namespace MWLua
|
||||
|
||||
sol::table initPostprocessingPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
sol::usertype<Shader> shader = context.mLua->sol().new_usertype<Shader>("Shader");
|
||||
sol::usertype<Shader> shader = lua.new_usertype<Shader>("Shader");
|
||||
shader[sol::meta_function::to_string] = [](const Shader& shader) { return shader.toString(); };
|
||||
|
||||
shader["enable"] = [context](Shader& shader, sol::optional<int> optPos) {
|
||||
|
@ -43,8 +43,8 @@ namespace MWLua
|
||||
{
|
||||
sol::table initRaceRecordBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table races(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table races(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::Race>(races, context);
|
||||
|
||||
auto raceT = lua.new_usertype<ESM::Race>("ESM3_Race");
|
||||
|
@ -39,7 +39,7 @@ namespace MWLua
|
||||
// Define a custom user type for the store.
|
||||
// Provide the interface of a read-only array.
|
||||
using StoreT = MWWorld::Store<T>;
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::usertype<StoreT> storeT = lua.new_usertype<StoreT>(recordName + "WorldStore");
|
||||
storeT[sol::meta_function::to_string] = [recordName](const StoreT& store) {
|
||||
return "{" + std::to_string(store.getSize()) + " " + recordName + " records}";
|
||||
|
@ -100,7 +100,7 @@ namespace MWLua
|
||||
{
|
||||
sol::table initAmbientPackage(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
if (lua["openmw_ambient"] != sol::nil)
|
||||
return lua["openmw_ambient"];
|
||||
|
||||
@ -171,7 +171,7 @@ namespace MWLua
|
||||
|
||||
sol::table initCoreSoundBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
api["isEnabled"] = []() { return MWBase::Environment::get().getSoundManager()->isEnabled(); };
|
||||
|
@ -54,7 +54,7 @@ namespace
|
||||
if (it != self->mStatsCache.end())
|
||||
return it->second;
|
||||
}
|
||||
return sol::make_object(context.mLua->sol(), getter(obj.ptr()));
|
||||
return sol::make_object(context.mLua->unsafeState(), getter(obj.ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,11 +531,12 @@ namespace MWLua
|
||||
{
|
||||
void addActorStatsBindings(sol::table& actor, const Context& context)
|
||||
{
|
||||
sol::table stats(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table stats(lua, sol::create);
|
||||
actor["stats"] = LuaUtil::makeReadOnly(stats);
|
||||
|
||||
auto skillIncreasesForAttributeStatsT
|
||||
= context.mLua->sol().new_usertype<SkillIncreasesForAttributeStats>("SkillIncreasesForAttributeStats");
|
||||
= lua.new_usertype<SkillIncreasesForAttributeStats>("SkillIncreasesForAttributeStats");
|
||||
for (const auto& attribute : MWBase::Environment::get().getESMStore()->get<ESM::Attribute>())
|
||||
{
|
||||
skillIncreasesForAttributeStatsT[ESM::RefId(attribute.mId).serializeText()] = sol::property(
|
||||
@ -546,8 +547,7 @@ namespace MWLua
|
||||
}
|
||||
// ESM::Class::specializationIndexToLuaId.at(rec.mData.mSpecialization)
|
||||
auto skillIncreasesForSpecializationStatsT
|
||||
= context.mLua->sol().new_usertype<SkillIncreasesForSpecializationStats>(
|
||||
"skillIncreasesForSpecializationStats");
|
||||
= lua.new_usertype<SkillIncreasesForSpecializationStats>("skillIncreasesForSpecializationStats");
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
std::string_view index = ESM::Class::specializationIndexToLuaId.at(i);
|
||||
@ -558,7 +558,7 @@ namespace MWLua
|
||||
});
|
||||
}
|
||||
|
||||
auto levelStatT = context.mLua->sol().new_usertype<LevelStat>("LevelStat");
|
||||
auto levelStatT = lua.new_usertype<LevelStat>("LevelStat");
|
||||
levelStatT["current"] = sol::property([context](const LevelStat& stat) { return stat.getCurrent(context); },
|
||||
[context](const LevelStat& stat, const sol::object& value) { stat.setCurrent(context, value); });
|
||||
levelStatT["progress"] = sol::property([context](const LevelStat& stat) { return stat.getProgress(context); },
|
||||
@ -569,32 +569,32 @@ namespace MWLua
|
||||
[](const LevelStat& stat) { return stat.getSkillIncreasesForSpecializationStats(); });
|
||||
stats["level"] = addIndexedAccessor<LevelStat>(0);
|
||||
|
||||
auto dynamicStatT = context.mLua->sol().new_usertype<DynamicStat>("DynamicStat");
|
||||
auto dynamicStatT = lua.new_usertype<DynamicStat>("DynamicStat");
|
||||
addProp(context, dynamicStatT, "base", &MWMechanics::DynamicStat<float>::getBase);
|
||||
addProp(context, dynamicStatT, "current", &MWMechanics::DynamicStat<float>::getCurrent);
|
||||
addProp(context, dynamicStatT, "modifier", &MWMechanics::DynamicStat<float>::getModifier);
|
||||
sol::table dynamic(context.mLua->sol(), sol::create);
|
||||
sol::table dynamic(lua, sol::create);
|
||||
stats["dynamic"] = LuaUtil::makeReadOnly(dynamic);
|
||||
dynamic["health"] = addIndexedAccessor<DynamicStat>(0);
|
||||
dynamic["magicka"] = addIndexedAccessor<DynamicStat>(1);
|
||||
dynamic["fatigue"] = addIndexedAccessor<DynamicStat>(2);
|
||||
|
||||
auto attributeStatT = context.mLua->sol().new_usertype<AttributeStat>("AttributeStat");
|
||||
auto attributeStatT = lua.new_usertype<AttributeStat>("AttributeStat");
|
||||
addProp(context, attributeStatT, "base", &MWMechanics::AttributeValue::getBase);
|
||||
addProp(context, attributeStatT, "damage", &MWMechanics::AttributeValue::getDamage);
|
||||
attributeStatT["modified"]
|
||||
= sol::readonly_property([=](const AttributeStat& stat) { return stat.getModified(context); });
|
||||
addProp(context, attributeStatT, "modifier", &MWMechanics::AttributeValue::getModifier);
|
||||
sol::table attributes(context.mLua->sol(), sol::create);
|
||||
sol::table attributes(lua, sol::create);
|
||||
stats["attributes"] = LuaUtil::makeReadOnly(attributes);
|
||||
for (const ESM::Attribute& attribute : MWBase::Environment::get().getESMStore()->get<ESM::Attribute>())
|
||||
attributes[ESM::RefId(attribute.mId).serializeText()] = addIndexedAccessor<AttributeStat>(attribute.mId);
|
||||
|
||||
auto aiStatT = context.mLua->sol().new_usertype<AIStat>("AIStat");
|
||||
auto aiStatT = lua.new_usertype<AIStat>("AIStat");
|
||||
addProp(context, aiStatT, "base", &MWMechanics::Stat<int>::getBase);
|
||||
addProp(context, aiStatT, "modifier", &MWMechanics::Stat<int>::getModifier);
|
||||
aiStatT["modified"] = sol::readonly_property([=](const AIStat& stat) { return stat.getModified(context); });
|
||||
sol::table ai(context.mLua->sol(), sol::create);
|
||||
sol::table ai(lua, sol::create);
|
||||
stats["ai"] = LuaUtil::makeReadOnly(ai);
|
||||
ai["alarm"] = addIndexedAccessor<AIStat>(MWMechanics::AiSetting::Alarm);
|
||||
ai["fight"] = addIndexedAccessor<AIStat>(MWMechanics::AiSetting::Fight);
|
||||
@ -604,13 +604,14 @@ namespace MWLua
|
||||
|
||||
void addNpcStatsBindings(sol::table& npc, const Context& context)
|
||||
{
|
||||
sol::table npcStats(context.mLua->sol(), sol::create);
|
||||
sol::table baseMeta(context.mLua->sol(), sol::create);
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table npcStats(lua, sol::create);
|
||||
sol::table baseMeta(lua, sol::create);
|
||||
baseMeta[sol::meta_function::index] = LuaUtil::getMutableFromReadOnly(npc["baseType"]["stats"]);
|
||||
npcStats[sol::metatable_key] = baseMeta;
|
||||
npc["stats"] = LuaUtil::makeReadOnly(npcStats);
|
||||
|
||||
auto skillStatT = context.mLua->sol().new_usertype<SkillStat>("SkillStat");
|
||||
auto skillStatT = lua.new_usertype<SkillStat>("SkillStat");
|
||||
addProp(context, skillStatT, "base", &MWMechanics::SkillValue::getBase);
|
||||
addProp(context, skillStatT, "damage", &MWMechanics::SkillValue::getDamage);
|
||||
skillStatT["modified"]
|
||||
@ -618,7 +619,7 @@ namespace MWLua
|
||||
addProp(context, skillStatT, "modifier", &MWMechanics::SkillValue::getModifier);
|
||||
skillStatT["progress"] = sol::property([context](const SkillStat& stat) { return stat.getProgress(context); },
|
||||
[context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); });
|
||||
sol::table skills(context.mLua->sol(), sol::create);
|
||||
sol::table skills(lua, sol::create);
|
||||
npcStats["skills"] = LuaUtil::makeReadOnly(skills);
|
||||
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||
skills[ESM::RefId(skill.mId).serializeText()] = addIndexedAccessor<SkillStat>(skill.mId);
|
||||
@ -626,7 +627,7 @@ namespace MWLua
|
||||
|
||||
sol::table initCoreStatsBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table statsApi(lua, sol::create);
|
||||
auto* vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
@ -635,7 +636,7 @@ namespace MWLua
|
||||
statsApi["Attribute"] = LuaUtil::makeReadOnly(attributes);
|
||||
statsApi["Attribute"][sol::metatable_key][sol::meta_function::to_string] = ESM::Attribute::getRecordType;
|
||||
|
||||
auto attributeT = context.mLua->sol().new_usertype<ESM::Attribute>("Attribute");
|
||||
auto attributeT = lua.new_usertype<ESM::Attribute>("Attribute");
|
||||
attributeT[sol::meta_function::to_string]
|
||||
= [](const ESM::Attribute& rec) { return "ESM3_Attribute[" + rec.mId.toDebugString() + "]"; };
|
||||
attributeT["id"] = sol::readonly_property(
|
||||
@ -653,7 +654,7 @@ namespace MWLua
|
||||
statsApi["Skill"] = LuaUtil::makeReadOnly(skills);
|
||||
statsApi["Skill"][sol::metatable_key][sol::meta_function::to_string] = ESM::Skill::getRecordType;
|
||||
|
||||
auto skillT = context.mLua->sol().new_usertype<ESM::Skill>("Skill");
|
||||
auto skillT = lua.new_usertype<ESM::Skill>("Skill");
|
||||
skillT[sol::meta_function::to_string]
|
||||
= [](const ESM::Skill& rec) { return "ESM3_Skill[" + rec.mId.toDebugString() + "]"; };
|
||||
skillT["id"] = sol::readonly_property(
|
||||
@ -683,7 +684,7 @@ namespace MWLua
|
||||
return res;
|
||||
});
|
||||
|
||||
auto schoolT = context.mLua->sol().new_usertype<ESM::MagicSchool>("MagicSchool");
|
||||
auto schoolT = lua.new_usertype<ESM::MagicSchool>("MagicSchool");
|
||||
schoolT[sol::meta_function::to_string]
|
||||
= [](const ESM::MagicSchool& rec) { return "ESM3_MagicSchool[" + rec.mName + "]"; };
|
||||
schoolT["name"]
|
||||
|
@ -43,7 +43,7 @@ namespace MWLua
|
||||
activator["createRecordDraft"] = tableToActivator;
|
||||
addRecordFunctionBinding<ESM::Activator>(activator, context);
|
||||
|
||||
sol::usertype<ESM::Activator> record = context.mLua->sol().new_usertype<ESM::Activator>("ESM3_Activator");
|
||||
sol::usertype<ESM::Activator> record = context.sol().new_usertype<ESM::Activator>("ESM3_Activator");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Activator& rec) { return "ESM3_Activator[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -172,13 +172,15 @@ namespace MWLua
|
||||
|
||||
void addActorBindings(sol::table actor, const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
actor["STANCE"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWMechanics::DrawState>({
|
||||
{ "Nothing", MWMechanics::DrawState::Nothing },
|
||||
{ "Weapon", MWMechanics::DrawState::Weapon },
|
||||
{ "Spell", MWMechanics::DrawState::Spell },
|
||||
}));
|
||||
actor["EQUIPMENT_SLOT"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>(
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWMechanics::DrawState>(lua,
|
||||
{
|
||||
{ "Nothing", MWMechanics::DrawState::Nothing },
|
||||
{ "Weapon", MWMechanics::DrawState::Weapon },
|
||||
{ "Spell", MWMechanics::DrawState::Spell },
|
||||
}));
|
||||
actor["EQUIPMENT_SLOT"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{ { "Helmet", MWWorld::InventoryStore::Slot_Helmet }, { "Cuirass", MWWorld::InventoryStore::Slot_Cuirass },
|
||||
{ "Greaves", MWWorld::InventoryStore::Slot_Greaves },
|
||||
{ "LeftPauldron", MWWorld::InventoryStore::Slot_LeftPauldron },
|
||||
|
@ -23,7 +23,7 @@ namespace MWLua
|
||||
void addActorServicesBindings(sol::usertype<T>& record, const Context& context)
|
||||
{
|
||||
record["servicesOffered"] = sol::readonly_property([context](const T& rec) -> sol::table {
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table providedServices(lua, sol::create);
|
||||
constexpr std::array<std::pair<int, std::string_view>, 19> serviceNames = { { { ESM::NPC::Spells,
|
||||
"Spells" },
|
||||
@ -51,7 +51,7 @@ namespace MWLua
|
||||
});
|
||||
|
||||
record["travelDestinations"] = sol::readonly_property([context](const T& rec) -> sol::table {
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table travelDests(lua, sol::create);
|
||||
if (!rec.getTransport().empty())
|
||||
{
|
||||
|
@ -20,18 +20,20 @@ namespace MWLua
|
||||
{
|
||||
void addApparatusBindings(sol::table apparatus, const Context& context)
|
||||
{
|
||||
apparatus["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "MortarPestle", ESM::Apparatus::MortarPestle },
|
||||
{ "Alembic", ESM::Apparatus::Alembic },
|
||||
{ "Calcinator", ESM::Apparatus::Calcinator },
|
||||
{ "Retort", ESM::Apparatus::Retort },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
apparatus["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "MortarPestle", ESM::Apparatus::MortarPestle },
|
||||
{ "Alembic", ESM::Apparatus::Alembic },
|
||||
{ "Calcinator", ESM::Apparatus::Calcinator },
|
||||
{ "Retort", ESM::Apparatus::Retort },
|
||||
}));
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Apparatus>(apparatus, context);
|
||||
|
||||
sol::usertype<ESM::Apparatus> record = context.mLua->sol().new_usertype<ESM::Apparatus>("ESM3_Apparatus");
|
||||
sol::usertype<ESM::Apparatus> record = lua.new_usertype<ESM::Apparatus>("ESM3_Apparatus");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Apparatus& rec) { return "ESM3_Apparatus[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -69,26 +69,28 @@ namespace MWLua
|
||||
{
|
||||
void addArmorBindings(sol::table armor, const Context& context)
|
||||
{
|
||||
armor["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "Helmet", ESM::Armor::Helmet },
|
||||
{ "Cuirass", ESM::Armor::Cuirass },
|
||||
{ "LPauldron", ESM::Armor::LPauldron },
|
||||
{ "RPauldron", ESM::Armor::RPauldron },
|
||||
{ "Greaves", ESM::Armor::Greaves },
|
||||
{ "Boots", ESM::Armor::Boots },
|
||||
{ "LGauntlet", ESM::Armor::LGauntlet },
|
||||
{ "RGauntlet", ESM::Armor::RGauntlet },
|
||||
{ "Shield", ESM::Armor::Shield },
|
||||
{ "LBracer", ESM::Armor::LBracer },
|
||||
{ "RBracer", ESM::Armor::RBracer },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
armor["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "Helmet", ESM::Armor::Helmet },
|
||||
{ "Cuirass", ESM::Armor::Cuirass },
|
||||
{ "LPauldron", ESM::Armor::LPauldron },
|
||||
{ "RPauldron", ESM::Armor::RPauldron },
|
||||
{ "Greaves", ESM::Armor::Greaves },
|
||||
{ "Boots", ESM::Armor::Boots },
|
||||
{ "LGauntlet", ESM::Armor::LGauntlet },
|
||||
{ "RGauntlet", ESM::Armor::RGauntlet },
|
||||
{ "Shield", ESM::Armor::Shield },
|
||||
{ "LBracer", ESM::Armor::LBracer },
|
||||
{ "RBracer", ESM::Armor::RBracer },
|
||||
}));
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Armor>(armor, context);
|
||||
|
||||
armor["createRecordDraft"] = tableToArmor;
|
||||
sol::usertype<ESM::Armor> record = context.mLua->sol().new_usertype<ESM::Armor>("ESM3_Armor");
|
||||
sol::usertype<ESM::Armor> record = lua.new_usertype<ESM::Armor>("ESM3_Armor");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -82,9 +82,10 @@ namespace MWLua
|
||||
{
|
||||
void addBookBindings(sol::table book, const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
// types.book.SKILL is deprecated (core.SKILL should be used instead)
|
||||
// TODO: Remove book.SKILL after branching 0.49
|
||||
sol::table skill(context.mLua->sol(), sol::create);
|
||||
sol::table skill(lua, sol::create);
|
||||
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
||||
book["createRecordDraft"] = tableToBook;
|
||||
for (int id = 0; id < ESM::Skill::Length; ++id)
|
||||
@ -97,7 +98,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Book>(book, context);
|
||||
|
||||
sol::usertype<ESM::Book> record = context.mLua->sol().new_usertype<ESM::Book>("ESM3_Book");
|
||||
sol::usertype<ESM::Book> record = lua.new_usertype<ESM::Book>("ESM3_Book");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Book& rec) { return "ESM3_Book[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -66,24 +66,26 @@ namespace MWLua
|
||||
{
|
||||
clothing["createRecordDraft"] = tableToClothing;
|
||||
|
||||
clothing["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "Amulet", ESM::Clothing::Amulet },
|
||||
{ "Belt", ESM::Clothing::Belt },
|
||||
{ "LGlove", ESM::Clothing::LGlove },
|
||||
{ "Pants", ESM::Clothing::Pants },
|
||||
{ "RGlove", ESM::Clothing::RGlove },
|
||||
{ "Ring", ESM::Clothing::Ring },
|
||||
{ "Robe", ESM::Clothing::Robe },
|
||||
{ "Shirt", ESM::Clothing::Shirt },
|
||||
{ "Shoes", ESM::Clothing::Shoes },
|
||||
{ "Skirt", ESM::Clothing::Skirt },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
clothing["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "Amulet", ESM::Clothing::Amulet },
|
||||
{ "Belt", ESM::Clothing::Belt },
|
||||
{ "LGlove", ESM::Clothing::LGlove },
|
||||
{ "Pants", ESM::Clothing::Pants },
|
||||
{ "RGlove", ESM::Clothing::RGlove },
|
||||
{ "Ring", ESM::Clothing::Ring },
|
||||
{ "Robe", ESM::Clothing::Robe },
|
||||
{ "Shirt", ESM::Clothing::Shirt },
|
||||
{ "Shoes", ESM::Clothing::Shoes },
|
||||
{ "Skirt", ESM::Clothing::Skirt },
|
||||
}));
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Clothing>(clothing, context);
|
||||
|
||||
sol::usertype<ESM::Clothing> record = context.mLua->sol().new_usertype<ESM::Clothing>("ESM3_Clothing");
|
||||
sol::usertype<ESM::Clothing> record = lua.new_usertype<ESM::Clothing>("ESM3_Clothing");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Clothing& rec) -> std::string { return "ESM3_Clothing[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -42,7 +42,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Container>(container, context);
|
||||
|
||||
sol::usertype<ESM::Container> record = context.mLua->sol().new_usertype<ESM::Container>("ESM3_Container");
|
||||
sol::usertype<ESM::Container> record = context.sol().new_usertype<ESM::Container>("ESM3_Container");
|
||||
record[sol::meta_function::to_string] = [](const ESM::Container& rec) -> std::string {
|
||||
return "ESM3_Container[" + rec.mId.toDebugString() + "]";
|
||||
};
|
||||
|
@ -20,16 +20,18 @@ namespace MWLua
|
||||
{
|
||||
void addCreatureBindings(sol::table creature, const Context& context)
|
||||
{
|
||||
creature["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "Creatures", ESM::Creature::Creatures },
|
||||
{ "Daedra", ESM::Creature::Daedra },
|
||||
{ "Undead", ESM::Creature::Undead },
|
||||
{ "Humanoid", ESM::Creature::Humanoid },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
creature["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "Creatures", ESM::Creature::Creatures },
|
||||
{ "Daedra", ESM::Creature::Daedra },
|
||||
{ "Undead", ESM::Creature::Undead },
|
||||
{ "Humanoid", ESM::Creature::Humanoid },
|
||||
}));
|
||||
|
||||
addRecordFunctionBinding<ESM::Creature>(creature, context);
|
||||
|
||||
sol::usertype<ESM::Creature> record = context.mLua->sol().new_usertype<ESM::Creature>("ESM3_Creature");
|
||||
sol::usertype<ESM::Creature> record = lua.new_usertype<ESM::Creature>("ESM3_Creature");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Creature& rec) { return "ESM3_Creature[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
@ -50,8 +52,7 @@ namespace MWLua
|
||||
record["magicSkill"] = sol::readonly_property([](const ESM::Creature& rec) -> int { return rec.mData.mMagic; });
|
||||
record["stealthSkill"]
|
||||
= sol::readonly_property([](const ESM::Creature& rec) -> int { return rec.mData.mStealth; });
|
||||
record["attack"] = sol::readonly_property([context](const ESM::Creature& rec) -> sol::table {
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
record["attack"] = sol::readonly_property([](sol::this_state lua, const ESM::Creature& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
int index = 1;
|
||||
for (auto attack : rec.mData.mAttack)
|
||||
|
@ -41,11 +41,13 @@ namespace MWLua
|
||||
|
||||
void addDoorBindings(sol::table door, const Context& context)
|
||||
{
|
||||
door["STATE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWWorld::DoorState>({
|
||||
{ "Idle", MWWorld::DoorState::Idle },
|
||||
{ "Opening", MWWorld::DoorState::Opening },
|
||||
{ "Closing", MWWorld::DoorState::Closing },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
door["STATE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, MWWorld::DoorState>(lua,
|
||||
{
|
||||
{ "Idle", MWWorld::DoorState::Idle },
|
||||
{ "Opening", MWWorld::DoorState::Opening },
|
||||
{ "Closing", MWWorld::DoorState::Closing },
|
||||
}));
|
||||
door["getDoorState"] = [](const Object& o) -> MWWorld::DoorState {
|
||||
const MWWorld::Ptr& door = doorPtr(o);
|
||||
return door.getClass().getDoorState(door);
|
||||
@ -99,7 +101,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Door>(door, context);
|
||||
|
||||
sol::usertype<ESM::Door> record = context.mLua->sol().new_usertype<ESM::Door>("ESM3_Door");
|
||||
sol::usertype<ESM::Door> record = lua.new_usertype<ESM::Door>("ESM3_Door");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Door& rec) -> std::string { return "ESM3_Door[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
@ -136,7 +138,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM4::Door>(door, context, "ESM4Door");
|
||||
|
||||
sol::usertype<ESM4::Door> record = context.mLua->sol().new_usertype<ESM4::Door>("ESM4_Door");
|
||||
sol::usertype<ESM4::Door> record = context.sol().new_usertype<ESM4::Door>("ESM4_Door");
|
||||
record[sol::meta_function::to_string] = [](const ESM4::Door& rec) -> std::string {
|
||||
return "ESM4_Door[" + ESM::RefId(rec.mId).toDebugString() + "]";
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Ingredient>(ingredient, context);
|
||||
|
||||
sol::usertype<ESM::Ingredient> record = context.mLua->sol().new_usertype<ESM::Ingredient>(("ESM3_Ingredient"));
|
||||
sol::usertype<ESM::Ingredient> record = context.sol().new_usertype<ESM::Ingredient>(("ESM3_Ingredient"));
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Ingredient& rec) { return "ESM3_Ingredient[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
@ -43,8 +43,8 @@ namespace MWLua
|
||||
record["weight"]
|
||||
= sol::readonly_property([](const ESM::Ingredient& rec) -> float { return rec.mData.mWeight; });
|
||||
record["value"] = sol::readonly_property([](const ESM::Ingredient& rec) -> int { return rec.mData.mValue; });
|
||||
record["effects"] = sol::readonly_property([context](const ESM::Ingredient& rec) -> sol::table {
|
||||
sol::table res(context.mLua->sol(), sol::create);
|
||||
record["effects"] = sol::readonly_property([](sol::this_state lua, const ESM::Ingredient& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
if (rec.mData.mEffectID[i] < 0)
|
||||
|
@ -23,7 +23,7 @@ namespace MWLua
|
||||
{
|
||||
void addLevelledCreatureBindings(sol::table list, const Context& context)
|
||||
{
|
||||
auto& state = context.mLua->sol();
|
||||
auto state = context.sol();
|
||||
auto item = state.new_usertype<ESM::LevelledListBase::LevelItem>("ESM3_LevelledListItem");
|
||||
item["id"] = sol::readonly_property(
|
||||
[](const ESM::LevelledListBase::LevelItem& rec) -> std::string { return rec.mId.serializeText(); });
|
||||
|
@ -84,7 +84,7 @@ namespace MWLua
|
||||
addRecordFunctionBinding<ESM::Light>(light, context);
|
||||
light["createRecordDraft"] = tableToLight;
|
||||
|
||||
sol::usertype<ESM::Light> record = context.mLua->sol().new_usertype<ESM::Light>("ESM3_Light");
|
||||
sol::usertype<ESM::Light> record = context.sol().new_usertype<ESM::Light>("ESM3_Light");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Light& rec) -> std::string { return "ESM3_Light[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -24,7 +24,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Lockpick>(lockpick, context);
|
||||
|
||||
sol::usertype<ESM::Lockpick> record = context.mLua->sol().new_usertype<ESM::Lockpick>("ESM3_Lockpick");
|
||||
sol::usertype<ESM::Lockpick> record = context.sol().new_usertype<ESM::Lockpick>("ESM3_Lockpick");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Lockpick& rec) { return "ESM3_Lockpick[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -75,8 +75,7 @@ namespace MWLua
|
||||
};
|
||||
miscellaneous["soul"] = miscellaneous["getSoul"]; // for compatibility; should be removed later
|
||||
|
||||
sol::usertype<ESM::Miscellaneous> record
|
||||
= context.mLua->sol().new_usertype<ESM::Miscellaneous>("ESM3_Miscellaneous");
|
||||
sol::usertype<ESM::Miscellaneous> record = context.sol().new_usertype<ESM::Miscellaneous>("ESM3_Miscellaneous");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Miscellaneous& rec) { return "ESM3_Miscellaneous[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"] = sol::readonly_property(
|
||||
|
@ -73,7 +73,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::NPC>(npc, context);
|
||||
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::state_view lua = context.sol();
|
||||
|
||||
sol::usertype<ESM::NPC> record = lua.new_usertype<ESM::NPC>("ESM3_NPC");
|
||||
record[sol::meta_function::to_string]
|
||||
|
@ -71,7 +71,8 @@ namespace MWLua
|
||||
|| dynamic_cast<const SelfObject*>(&player) != nullptr;
|
||||
return Quests{ .mMutable = allowChanges };
|
||||
};
|
||||
sol::usertype<Quests> quests = context.mLua->sol().new_usertype<Quests>("Quests");
|
||||
sol::state_view lua = context.sol();
|
||||
sol::usertype<Quests> quests = lua.new_usertype<Quests>("Quests");
|
||||
quests[sol::meta_function::to_string] = [](const Quests& quests) { return "Quests"; };
|
||||
quests[sol::meta_function::index] = [](const Quests& quests, std::string_view questId) -> sol::optional<Quest> {
|
||||
ESM::RefId quest = ESM::RefId::deserializeText(questId);
|
||||
@ -94,7 +95,7 @@ namespace MWLua
|
||||
};
|
||||
};
|
||||
|
||||
sol::usertype<Quest> quest = context.mLua->sol().new_usertype<Quest>("Quest");
|
||||
sol::usertype<Quest> quest = lua.new_usertype<Quest>("Quest");
|
||||
quest[sol::meta_function::to_string]
|
||||
= [](const Quest& quest) { return "Quest[" + quest.mQuestId.serializeText() + "]"; };
|
||||
|
||||
@ -146,15 +147,16 @@ namespace MWLua
|
||||
};
|
||||
|
||||
player["CONTROL_SWITCH"]
|
||||
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, std::string_view>({
|
||||
{ "Controls", "playercontrols" },
|
||||
{ "Fighting", "playerfighting" },
|
||||
{ "Jumping", "playerjumping" },
|
||||
{ "Looking", "playerlooking" },
|
||||
{ "Magic", "playermagic" },
|
||||
{ "ViewMode", "playerviewswitch" },
|
||||
{ "VanityMode", "vanitymode" },
|
||||
}));
|
||||
= LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, std::string_view>(lua,
|
||||
{
|
||||
{ "Controls", "playercontrols" },
|
||||
{ "Fighting", "playerfighting" },
|
||||
{ "Jumping", "playerjumping" },
|
||||
{ "Looking", "playerlooking" },
|
||||
{ "Magic", "playermagic" },
|
||||
{ "ViewMode", "playerviewswitch" },
|
||||
{ "VanityMode", "vanitymode" },
|
||||
}));
|
||||
|
||||
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||
player["getControlSwitch"] = [input](const Object& player, std::string_view key) {
|
||||
|
@ -69,7 +69,7 @@ namespace MWLua
|
||||
potion["createRecordDraft"] = tableToPotion;
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
sol::usertype<ESM::Potion> record = context.mLua->sol().new_usertype<ESM::Potion>("ESM3_Potion");
|
||||
sol::usertype<ESM::Potion> record = context.sol().new_usertype<ESM::Potion>("ESM3_Potion");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Potion& rec) { return "ESM3_Potion[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
@ -84,8 +84,8 @@ namespace MWLua
|
||||
[](const ESM::Potion& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); });
|
||||
record["weight"] = sol::readonly_property([](const ESM::Potion& rec) -> float { return rec.mData.mWeight; });
|
||||
record["value"] = sol::readonly_property([](const ESM::Potion& rec) -> int { return rec.mData.mValue; });
|
||||
record["effects"] = sol::readonly_property([context](const ESM::Potion& rec) -> sol::table {
|
||||
sol::table res(context.mLua->sol(), sol::create);
|
||||
record["effects"] = sol::readonly_property([](sol::this_state lua, const ESM::Potion& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
for (size_t i = 0; i < rec.mEffects.mList.size(); ++i)
|
||||
res[LuaUtil::toLuaIndex(i)] = rec.mEffects.mList[i]; // ESM::IndexedENAMstruct (effect params)
|
||||
return res;
|
||||
|
@ -24,7 +24,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Probe>(probe, context);
|
||||
|
||||
sol::usertype<ESM::Probe> record = context.mLua->sol().new_usertype<ESM::Probe>("ESM3_Probe");
|
||||
sol::usertype<ESM::Probe> record = context.sol().new_usertype<ESM::Probe>("ESM3_Probe");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Probe& rec) { return "ESM3_Probe[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -24,7 +24,7 @@ namespace MWLua
|
||||
|
||||
addRecordFunctionBinding<ESM::Repair>(repair, context);
|
||||
|
||||
sol::usertype<ESM::Repair> record = context.mLua->sol().new_usertype<ESM::Repair>("ESM3_Repair");
|
||||
sol::usertype<ESM::Repair> record = context.sol().new_usertype<ESM::Repair>("ESM3_Repair");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Repair& rec) { return "ESM3_Repair[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -19,7 +19,7 @@ namespace MWLua
|
||||
{
|
||||
addRecordFunctionBinding<ESM::Static>(stat, context);
|
||||
|
||||
sol::usertype<ESM::Static> record = context.mLua->sol().new_usertype<ESM::Static>("ESM3_Static");
|
||||
sol::usertype<ESM::Static> record = context.sol().new_usertype<ESM::Static>("ESM3_Static");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -21,7 +21,7 @@ namespace MWLua
|
||||
{
|
||||
addRecordFunctionBinding<ESM4::Terminal>(term, context, "ESM4Terminal");
|
||||
|
||||
sol::usertype<ESM4::Terminal> record = context.mLua->sol().new_usertype<ESM4::Terminal>("ESM4_Terminal");
|
||||
sol::usertype<ESM4::Terminal> record = context.sol().new_usertype<ESM4::Terminal>("ESM4_Terminal");
|
||||
record[sol::meta_function::to_string] = [](const ESM4::Terminal& rec) -> std::string {
|
||||
return "ESM4_Terminal[" + ESM::RefId(rec.mId).toDebugString() + "]";
|
||||
};
|
||||
|
@ -165,22 +165,22 @@ namespace MWLua
|
||||
|
||||
sol::table initTypesPackage(const Context& context)
|
||||
{
|
||||
auto* lua = context.mLua;
|
||||
auto lua = context.sol();
|
||||
|
||||
if (lua->sol()["openmw_types"] != sol::nil)
|
||||
return lua->sol()["openmw_types"];
|
||||
if (lua["openmw_types"] != sol::nil)
|
||||
return lua["openmw_types"];
|
||||
|
||||
sol::table types(lua->sol(), sol::create);
|
||||
sol::table types(lua, sol::create);
|
||||
auto addType = [&](std::string_view name, std::vector<ESM::RecNameInts> recTypes,
|
||||
std::optional<std::string_view> base = std::nullopt) -> sol::table {
|
||||
sol::table t(lua->sol(), sol::create);
|
||||
sol::table t(lua, sol::create);
|
||||
sol::table ro = LuaUtil::makeReadOnly(t);
|
||||
sol::table meta = ro[sol::metatable_key];
|
||||
meta[sol::meta_function::to_string] = [name]() { return name; };
|
||||
if (base)
|
||||
{
|
||||
t["baseType"] = types[*base];
|
||||
sol::table baseMeta(lua->sol(), sol::create);
|
||||
sol::table baseMeta(lua, sol::create);
|
||||
baseMeta[sol::meta_function::index] = LuaUtil::getMutableFromReadOnly(types[*base]);
|
||||
t[sol::metatable_key] = baseMeta;
|
||||
}
|
||||
@ -251,8 +251,8 @@ namespace MWLua
|
||||
addType(ObjectTypeName::ESM4Tree, { ESM::REC_TREE4 });
|
||||
addType(ObjectTypeName::ESM4Weapon, { ESM::REC_WEAP4 });
|
||||
|
||||
sol::table typeToPackage = getTypeToPackageTable(context.mLua->sol());
|
||||
sol::table packageToType = getPackageToTypeTable(context.mLua->sol());
|
||||
sol::table typeToPackage = getTypeToPackageTable(lua);
|
||||
sol::table packageToType = getPackageToTypeTable(lua);
|
||||
for (const auto& [type, name] : luaObjectTypeInfo)
|
||||
{
|
||||
sol::object t = types[name];
|
||||
@ -262,7 +262,7 @@ namespace MWLua
|
||||
packageToType[t] = type;
|
||||
}
|
||||
|
||||
lua->sol()["openmw_types"] = LuaUtil::makeReadOnly(types);
|
||||
return lua->sol()["openmw_types"];
|
||||
lua["openmw_types"] = LuaUtil::makeReadOnly(types);
|
||||
return lua["openmw_types"];
|
||||
}
|
||||
}
|
||||
|
@ -99,29 +99,31 @@ namespace MWLua
|
||||
{
|
||||
void addWeaponBindings(sol::table weapon, const Context& context)
|
||||
{
|
||||
weapon["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand },
|
||||
{ "LongBladeOneHand", ESM::Weapon::LongBladeOneHand },
|
||||
{ "LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand },
|
||||
{ "BluntOneHand", ESM::Weapon::BluntOneHand },
|
||||
{ "BluntTwoClose", ESM::Weapon::BluntTwoClose },
|
||||
{ "BluntTwoWide", ESM::Weapon::BluntTwoWide },
|
||||
{ "SpearTwoWide", ESM::Weapon::SpearTwoWide },
|
||||
{ "AxeOneHand", ESM::Weapon::AxeOneHand },
|
||||
{ "AxeTwoHand", ESM::Weapon::AxeTwoHand },
|
||||
{ "MarksmanBow", ESM::Weapon::MarksmanBow },
|
||||
{ "MarksmanCrossbow", ESM::Weapon::MarksmanCrossbow },
|
||||
{ "MarksmanThrown", ESM::Weapon::MarksmanThrown },
|
||||
{ "Arrow", ESM::Weapon::Arrow },
|
||||
{ "Bolt", ESM::Weapon::Bolt },
|
||||
}));
|
||||
sol::state_view lua = context.sol();
|
||||
weapon["TYPE"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, int>(lua,
|
||||
{
|
||||
{ "ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand },
|
||||
{ "LongBladeOneHand", ESM::Weapon::LongBladeOneHand },
|
||||
{ "LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand },
|
||||
{ "BluntOneHand", ESM::Weapon::BluntOneHand },
|
||||
{ "BluntTwoClose", ESM::Weapon::BluntTwoClose },
|
||||
{ "BluntTwoWide", ESM::Weapon::BluntTwoWide },
|
||||
{ "SpearTwoWide", ESM::Weapon::SpearTwoWide },
|
||||
{ "AxeOneHand", ESM::Weapon::AxeOneHand },
|
||||
{ "AxeTwoHand", ESM::Weapon::AxeTwoHand },
|
||||
{ "MarksmanBow", ESM::Weapon::MarksmanBow },
|
||||
{ "MarksmanCrossbow", ESM::Weapon::MarksmanCrossbow },
|
||||
{ "MarksmanThrown", ESM::Weapon::MarksmanThrown },
|
||||
{ "Arrow", ESM::Weapon::Arrow },
|
||||
{ "Bolt", ESM::Weapon::Bolt },
|
||||
}));
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Weapon>(weapon, context);
|
||||
weapon["createRecordDraft"] = tableToWeapon;
|
||||
|
||||
sol::usertype<ESM::Weapon> record = context.mLua->sol().new_usertype<ESM::Weapon>("ESM3_Weapon");
|
||||
sol::usertype<ESM::Weapon> record = lua.new_usertype<ESM::Weapon>("ESM3_Weapon");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Weapon& rec) -> std::string { return "ESM3_Weapon[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -82,11 +82,12 @@ namespace MWLua
|
||||
|
||||
sol::table registerUiApi(const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
bool menu = context.mType == Context::Menu;
|
||||
|
||||
MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
|
||||
|
||||
sol::table api = context.mLua->newTable();
|
||||
sol::table api(lua, sol::create);
|
||||
api["_setHudVisibility"] = [luaManager = context.mLuaManager](bool state) {
|
||||
luaManager->addAction([state] { MWBase::Environment::get().getWindowManager()->setHudVisibility(state); });
|
||||
};
|
||||
@ -107,12 +108,13 @@ namespace MWLua
|
||||
}
|
||||
luaManager->addUIMessage(message, mode);
|
||||
};
|
||||
api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string, Misc::Color>({
|
||||
{ "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) },
|
||||
{ "Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1)) },
|
||||
{ "Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1)) },
|
||||
{ "Info", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Info.substr(1)) },
|
||||
}));
|
||||
api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string, Misc::Color>(lua,
|
||||
{
|
||||
{ "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) },
|
||||
{ "Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1)) },
|
||||
{ "Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1)) },
|
||||
{ "Info", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Info.substr(1)) },
|
||||
}));
|
||||
api["printToConsole"]
|
||||
= [luaManager = context.mLuaManager](const std::string& message, const Misc::Color& color) {
|
||||
luaManager->addInGameConsoleMessage(message + "\n", color);
|
||||
@ -150,7 +152,7 @@ namespace MWLua
|
||||
};
|
||||
api["_getMenuTransparency"] = []() -> float { return Settings::gui().mMenuTransparency; };
|
||||
|
||||
sol::table layersTable = context.mLua->newTable();
|
||||
sol::table layersTable(lua, sol::create);
|
||||
layersTable["indexOf"] = [](std::string_view name) -> sol::optional<size_t> {
|
||||
size_t index = LuaUi::Layer::indexOf(name);
|
||||
if (index == LuaUi::Layer::count())
|
||||
@ -202,14 +204,14 @@ namespace MWLua
|
||||
}
|
||||
api["layers"] = layers;
|
||||
|
||||
sol::table typeTable = context.mLua->newTable();
|
||||
sol::table typeTable(lua, sol::create);
|
||||
for (const auto& it : LuaUi::widgetTypeToName())
|
||||
typeTable.set(it.second, it.first);
|
||||
api["TYPE"] = LuaUtil::makeStrictReadOnly(typeTable);
|
||||
|
||||
api["ALIGNMENT"] = LuaUtil::makeStrictReadOnly(
|
||||
context.mLua->tableFromPairs<std::string_view, LuaUi::Alignment>({ { "Start", LuaUi::Alignment::Start },
|
||||
{ "Center", LuaUi::Alignment::Center }, { "End", LuaUi::Alignment::End } }));
|
||||
api["ALIGNMENT"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string_view, LuaUi::Alignment>(lua,
|
||||
{ { "Start", LuaUi::Alignment::Start }, { "Center", LuaUi::Alignment::Center },
|
||||
{ "End", LuaUi::Alignment::End } }));
|
||||
|
||||
api["registerSettingsPage"] = &LuaUi::registerSettingsPage;
|
||||
api["removeSettingsPage"] = &LuaUi::removeSettingsPage;
|
||||
@ -297,7 +299,7 @@ namespace MWLua
|
||||
{
|
||||
if (context.initializeOnce("openmw_ui_usertypes"))
|
||||
{
|
||||
auto element = context.mLua->sol().new_usertype<LuaUi::Element>("UiElement");
|
||||
auto element = context.sol().new_usertype<LuaUi::Element>("UiElement");
|
||||
element[sol::meta_function::to_string] = [](const LuaUi::Element& element) {
|
||||
std::stringstream res;
|
||||
res << "UiElement";
|
||||
@ -321,7 +323,7 @@ namespace MWLua
|
||||
[element] { wrapAction(element, [&] { LuaUi::Element::erase(element.get()); }); }, "Destroy UI");
|
||||
};
|
||||
|
||||
auto uiLayer = context.mLua->sol().new_usertype<LuaUi::Layer>("UiLayer");
|
||||
auto uiLayer = context.sol().new_usertype<LuaUi::Layer>("UiLayer");
|
||||
uiLayer["name"]
|
||||
= sol::readonly_property([](LuaUi::Layer& self) -> std::string_view { return self.name(); });
|
||||
uiLayer["size"] = sol::readonly_property([](LuaUi::Layer& self) { return self.size(); });
|
||||
|
@ -68,7 +68,7 @@ namespace MWLua
|
||||
Log(Debug::Verbose) << "Read a large data chunk (" << size << " bytes) from '" << file.mFileName << "'.";
|
||||
}
|
||||
|
||||
sol::object readFile(LuaUtil::LuaState* lua, FileHandle& file)
|
||||
sol::object readFile(sol::this_state lua, FileHandle& file)
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (file.mFilePtr && file.mFilePtr->peek() != EOF)
|
||||
@ -76,34 +76,34 @@ namespace MWLua
|
||||
|
||||
auto result = os.str();
|
||||
printLargeDataMessage(file, result.size());
|
||||
return sol::make_object<std::string>(lua->sol(), std::move(result));
|
||||
return sol::make_object<std::string>(lua, std::move(result));
|
||||
}
|
||||
|
||||
sol::object readLineFromFile(LuaUtil::LuaState* lua, FileHandle& file)
|
||||
sol::object readLineFromFile(sol::this_state lua, FileHandle& file)
|
||||
{
|
||||
std::string result;
|
||||
if (file.mFilePtr && std::getline(*file.mFilePtr, result))
|
||||
{
|
||||
printLargeDataMessage(file, result.size());
|
||||
return sol::make_object<std::string>(lua->sol(), result);
|
||||
return sol::make_object<std::string>(lua, result);
|
||||
}
|
||||
|
||||
return sol::nil;
|
||||
}
|
||||
|
||||
sol::object readNumberFromFile(LuaUtil::LuaState* lua, Files::IStreamPtr& file)
|
||||
sol::object readNumberFromFile(sol::this_state lua, Files::IStreamPtr& file)
|
||||
{
|
||||
double number = 0;
|
||||
if (file && *file >> number)
|
||||
return sol::make_object<double>(lua->sol(), number);
|
||||
return sol::make_object<double>(lua, number);
|
||||
|
||||
return sol::nil;
|
||||
}
|
||||
|
||||
sol::object readCharactersFromFile(LuaUtil::LuaState* lua, FileHandle& file, size_t count)
|
||||
sol::object readCharactersFromFile(sol::this_state lua, FileHandle& file, size_t count)
|
||||
{
|
||||
if (count <= 0 && file.mFilePtr->peek() != EOF)
|
||||
return sol::make_object<std::string>(lua->sol(), std::string());
|
||||
return sol::make_object<std::string>(lua, std::string());
|
||||
|
||||
auto bytesLeft = getBytesLeftInStream(file.mFilePtr);
|
||||
if (bytesLeft <= 0)
|
||||
@ -116,7 +116,7 @@ namespace MWLua
|
||||
if (file.mFilePtr->read(&result[0], count))
|
||||
{
|
||||
printLargeDataMessage(file, result.size());
|
||||
return sol::make_object<std::string>(lua->sol(), result);
|
||||
return sol::make_object<std::string>(lua, result);
|
||||
}
|
||||
|
||||
return sol::nil;
|
||||
@ -131,7 +131,7 @@ namespace MWLua
|
||||
}
|
||||
|
||||
sol::variadic_results seek(
|
||||
LuaUtil::LuaState* lua, FileHandle& self, std::ios_base::seekdir dir, std::streamoff off)
|
||||
sol::this_state lua, FileHandle& self, std::ios_base::seekdir dir, std::streamoff off)
|
||||
{
|
||||
sol::variadic_results values;
|
||||
try
|
||||
@ -141,16 +141,16 @@ namespace MWLua
|
||||
{
|
||||
auto msg = "Failed to seek in file '" + self.mFileName + "'";
|
||||
values.push_back(sol::nil);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(lua, msg));
|
||||
}
|
||||
else
|
||||
values.push_back(sol::make_object<std::streampos>(lua->sol(), self.mFilePtr->tellg()));
|
||||
values.push_back(sol::make_object<std::streampos>(lua, self.mFilePtr->tellg()));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto msg = "Failed to seek in file '" + self.mFileName + "': " + std::string(e.what());
|
||||
values.push_back(sol::nil);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(lua, msg));
|
||||
}
|
||||
|
||||
return values;
|
||||
@ -159,18 +159,18 @@ namespace MWLua
|
||||
|
||||
sol::table initVFSPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::table api(context.mLua->unsafeState(), sol::create);
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
sol::usertype<FileHandle> handle = context.mLua->sol().new_usertype<FileHandle>("FileHandle");
|
||||
sol::usertype<FileHandle> handle = context.sol().new_usertype<FileHandle>("FileHandle");
|
||||
handle["fileName"]
|
||||
= sol::readonly_property([](const FileHandle& self) -> std::string_view { return self.mFileName; });
|
||||
handle[sol::meta_function::to_string] = [](const FileHandle& self) {
|
||||
return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}";
|
||||
};
|
||||
handle["seek"] = sol::overload(
|
||||
[lua = context.mLua](FileHandle& self, std::string_view whence, sol::optional<long> offset) {
|
||||
[](sol::this_state lua, FileHandle& self, std::string_view whence, sol::optional<long> offset) {
|
||||
validateFile(self);
|
||||
|
||||
auto off = static_cast<std::streamoff>(offset.value_or(0));
|
||||
@ -178,21 +178,21 @@ namespace MWLua
|
||||
|
||||
return seek(lua, self, dir, off);
|
||||
},
|
||||
[lua = context.mLua](FileHandle& self, sol::optional<long> offset) {
|
||||
[](sol::this_state lua, FileHandle& self, sol::optional<long> offset) {
|
||||
validateFile(self);
|
||||
|
||||
auto off = static_cast<std::streamoff>(offset.value_or(0));
|
||||
|
||||
return seek(lua, self, std::ios_base::cur, off);
|
||||
});
|
||||
handle["lines"] = [lua = context.mLua](FileHandle& self) {
|
||||
handle["lines"] = [](sol::this_state lua, FileHandle& self) {
|
||||
return sol::as_function([&lua, &self]() mutable {
|
||||
validateFile(self);
|
||||
return readLineFromFile(lua, self);
|
||||
});
|
||||
};
|
||||
|
||||
api["lines"] = [lua = context.mLua, vfs](std::string_view fileName) {
|
||||
api["lines"] = [vfs](sol::this_state lua, std::string_view fileName) {
|
||||
auto normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
return sol::as_function(
|
||||
[lua, file = FileHandle(vfs->getNormalized(normalizedName), normalizedName)]() mutable {
|
||||
@ -205,7 +205,7 @@ namespace MWLua
|
||||
});
|
||||
};
|
||||
|
||||
handle["close"] = [lua = context.mLua](FileHandle& self) {
|
||||
handle["close"] = [](lua_State* L, FileHandle& self) {
|
||||
sol::variadic_results values;
|
||||
try
|
||||
{
|
||||
@ -214,22 +214,22 @@ namespace MWLua
|
||||
{
|
||||
auto msg = "Can not close file '" + self.mFileName + "': file handle is still opened.";
|
||||
values.push_back(sol::nil);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(L, msg));
|
||||
}
|
||||
else
|
||||
values.push_back(sol::make_object<bool>(lua->sol(), true));
|
||||
values.push_back(sol::make_object<bool>(L, true));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto msg = "Can not close file '" + self.mFileName + "': " + std::string(e.what());
|
||||
values.push_back(sol::nil);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(L, msg));
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
handle["read"] = [lua = context.mLua](FileHandle& self, const sol::variadic_args args) {
|
||||
handle["read"] = [](sol::this_state lua, FileHandle& self, const sol::variadic_args args) {
|
||||
validateFile(self);
|
||||
|
||||
if (args.size() > sMaximumReadArguments)
|
||||
@ -297,25 +297,25 @@ namespace MWLua
|
||||
{
|
||||
auto msg = "Error when handling '" + self.mFileName + "': can not read data for argument #"
|
||||
+ std::to_string(i);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(lua, msg));
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
api["open"] = [lua = context.mLua, vfs](std::string_view fileName) {
|
||||
api["open"] = [vfs](sol::this_state lua, std::string_view fileName) {
|
||||
sol::variadic_results values;
|
||||
try
|
||||
{
|
||||
auto normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
auto handle = FileHandle(vfs->getNormalized(normalizedName), normalizedName);
|
||||
values.push_back(sol::make_object<FileHandle>(lua->sol(), std::move(handle)));
|
||||
values.push_back(sol::make_object<FileHandle>(lua, std::move(handle)));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
auto msg = "Can not open file: " + std::string(e.what());
|
||||
values.push_back(sol::nil);
|
||||
values.push_back(sol::make_object<std::string>(lua->sol(), msg));
|
||||
values.push_back(sol::make_object<std::string>(lua, msg));
|
||||
}
|
||||
|
||||
return values;
|
||||
|
@ -102,7 +102,8 @@ namespace MWLua
|
||||
|
||||
const MWWorld::Store<ESM::Cell>* cells3Store = &MWBase::Environment::get().getESMStore()->get<ESM::Cell>();
|
||||
const MWWorld::Store<ESM4::Cell>* cells4Store = &MWBase::Environment::get().getESMStore()->get<ESM4::Cell>();
|
||||
sol::usertype<CellsStore> cells = context.mLua->sol().new_usertype<CellsStore>("Cells");
|
||||
auto view = context.sol();
|
||||
sol::usertype<CellsStore> cells = view.new_usertype<CellsStore>("Cells");
|
||||
cells[sol::meta_function::length]
|
||||
= [cells3Store, cells4Store](const CellsStore&) { return cells3Store->getSize() + cells4Store->getSize(); };
|
||||
cells[sol::meta_function::index]
|
||||
@ -124,14 +125,14 @@ namespace MWLua
|
||||
cellRecord->mId, /*forceLoad=*/false) };
|
||||
}
|
||||
};
|
||||
cells[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||
cells[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||
cells[sol::meta_function::pairs] = view["ipairsForArray"].template get<sol::function>();
|
||||
cells[sol::meta_function::ipairs] = view["ipairsForArray"].template get<sol::function>();
|
||||
api["cells"] = CellsStore{};
|
||||
}
|
||||
|
||||
sol::table initWorldPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
sol::table api(context.mLua->unsafeState(), sol::create);
|
||||
|
||||
addCoreTimeBindings(api, context);
|
||||
addWorldTimeBindings(api, context);
|
||||
|
@ -183,121 +183,125 @@ namespace LuaUtil
|
||||
if (sProfilerEnabled)
|
||||
lua_sethook(mLuaHolder.get(), &countHook, LUA_MASKCOUNT, countHookStep);
|
||||
|
||||
mSol.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::bit32, sol::lib::string,
|
||||
sol::lib::table, sol::lib::os, sol::lib::debug);
|
||||
protectedCall([&](LuaView& view) {
|
||||
auto& sol = view.sol();
|
||||
sol.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::math, sol::lib::bit32, sol::lib::string,
|
||||
sol::lib::table, sol::lib::os, sol::lib::debug);
|
||||
|
||||
#ifndef NO_LUAJIT
|
||||
mSol.open_libraries(sol::lib::jit);
|
||||
sol.open_libraries(sol::lib::jit);
|
||||
#endif // NO_LUAJIT
|
||||
|
||||
mSol["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
||||
mSol["math"]["randomseed"] = [] {};
|
||||
sol["math"]["randomseed"](static_cast<unsigned>(std::time(nullptr)));
|
||||
sol["math"]["randomseed"] = [] {};
|
||||
|
||||
mSol["utf8"] = LuaUtf8::initUtf8Package(mSol);
|
||||
sol["utf8"] = LuaUtf8::initUtf8Package(sol);
|
||||
|
||||
mSol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
|
||||
sol["writeToLog"] = [](std::string_view s) { Log(Debug::Level::Info) << s; };
|
||||
|
||||
mSol["setEnvironment"]
|
||||
= [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); };
|
||||
mSol["loadFromVFS"] = [this](std::string_view packageName) {
|
||||
return loadScriptAndCache(packageNameToVfsPath(packageName, mVFS));
|
||||
};
|
||||
mSol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); };
|
||||
sol["setEnvironment"]
|
||||
= [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); };
|
||||
sol["loadFromVFS"] = [this](std::string_view packageName) {
|
||||
return loadScriptAndCache(packageNameToVfsPath(packageName, mVFS));
|
||||
};
|
||||
sol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); };
|
||||
|
||||
// Some fixes for compatibility between different Lua versions
|
||||
if (mSol["unpack"] == sol::nil)
|
||||
mSol["unpack"] = mSol["table"]["unpack"];
|
||||
else if (mSol["table"]["unpack"] == sol::nil)
|
||||
mSol["table"]["unpack"] = mSol["unpack"];
|
||||
if (LUA_VERSION_NUM <= 501)
|
||||
{
|
||||
mSol.script(R"(
|
||||
local _pairs = pairs
|
||||
local _ipairs = ipairs
|
||||
pairs = function(v) return (rawget(getmetatable(v) or {}, '__pairs') or _pairs)(v) end
|
||||
ipairs = function(v) return (rawget(getmetatable(v) or {}, '__ipairs') or _ipairs)(v) end
|
||||
// Some fixes for compatibility between different Lua versions
|
||||
if (sol["unpack"] == sol::nil)
|
||||
sol["unpack"] = sol["table"]["unpack"];
|
||||
else if (sol["table"]["unpack"] == sol::nil)
|
||||
sol["table"]["unpack"] = sol["unpack"];
|
||||
if (LUA_VERSION_NUM <= 501)
|
||||
{
|
||||
sol.script(R"(
|
||||
local _pairs = pairs
|
||||
local _ipairs = ipairs
|
||||
pairs = function(v) return (rawget(getmetatable(v) or {}, '__pairs') or _pairs)(v) end
|
||||
ipairs = function(v) return (rawget(getmetatable(v) or {}, '__ipairs') or _ipairs)(v) end
|
||||
)");
|
||||
}
|
||||
|
||||
sol.script(R"(
|
||||
local printToLog = function(...)
|
||||
local strs = {}
|
||||
for i = 1, select('#', ...) do
|
||||
strs[i] = tostring(select(i, ...))
|
||||
end
|
||||
return writeToLog(table.concat(strs, '\t'))
|
||||
end
|
||||
printGen = function(name) return function(...) return printToLog(name, ...) end end
|
||||
|
||||
function requireGen(env, loaded, loadFn)
|
||||
return function(packageName)
|
||||
local p = loaded[packageName]
|
||||
if p == nil then
|
||||
local loader = loadFn(packageName)
|
||||
setEnvironment(env, loader)
|
||||
p = loader(packageName)
|
||||
loaded[packageName] = p
|
||||
end
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
function createStrictIndexFn(tbl)
|
||||
return function(_, key)
|
||||
local res = tbl[key]
|
||||
if res ~= nil then
|
||||
return res
|
||||
else
|
||||
error('Key not found: '..tostring(key), 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
function pairsForReadOnly(v)
|
||||
local nextFn, t, firstKey = pairs(getmetatable(v).t)
|
||||
return function(_, k) return nextFn(t, k) end, v, firstKey
|
||||
end
|
||||
function ipairsForReadOnly(v)
|
||||
local nextFn, t, firstKey = ipairs(getmetatable(v).t)
|
||||
return function(_, k) return nextFn(t, k) end, v, firstKey
|
||||
end
|
||||
function lenForReadOnly(v)
|
||||
return #getmetatable(v).t
|
||||
end
|
||||
local function nextForArray(array, index)
|
||||
index = (index or 0) + 1
|
||||
if index <= #array then
|
||||
return index, array[index]
|
||||
end
|
||||
end
|
||||
function ipairsForArray(array)
|
||||
return nextForArray, array, 0
|
||||
end
|
||||
|
||||
getmetatable('').__metatable = false
|
||||
getSafeMetatable = function(v)
|
||||
if type(v) ~= 'table' then error('getmetatable is allowed only for tables', 2) end
|
||||
return getmetatable(v)
|
||||
end
|
||||
)");
|
||||
}
|
||||
|
||||
mSol.script(R"(
|
||||
local printToLog = function(...)
|
||||
local strs = {}
|
||||
for i = 1, select('#', ...) do
|
||||
strs[i] = tostring(select(i, ...))
|
||||
end
|
||||
return writeToLog(table.concat(strs, '\t'))
|
||||
end
|
||||
printGen = function(name) return function(...) return printToLog(name, ...) end end
|
||||
|
||||
function requireGen(env, loaded, loadFn)
|
||||
return function(packageName)
|
||||
local p = loaded[packageName]
|
||||
if p == nil then
|
||||
local loader = loadFn(packageName)
|
||||
setEnvironment(env, loader)
|
||||
p = loader(packageName)
|
||||
loaded[packageName] = p
|
||||
end
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
function createStrictIndexFn(tbl)
|
||||
return function(_, key)
|
||||
local res = tbl[key]
|
||||
if res ~= nil then
|
||||
return res
|
||||
else
|
||||
error('Key not found: '..tostring(key), 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
function pairsForReadOnly(v)
|
||||
local nextFn, t, firstKey = pairs(getmetatable(v).t)
|
||||
return function(_, k) return nextFn(t, k) end, v, firstKey
|
||||
end
|
||||
function ipairsForReadOnly(v)
|
||||
local nextFn, t, firstKey = ipairs(getmetatable(v).t)
|
||||
return function(_, k) return nextFn(t, k) end, v, firstKey
|
||||
end
|
||||
function lenForReadOnly(v)
|
||||
return #getmetatable(v).t
|
||||
end
|
||||
local function nextForArray(array, index)
|
||||
index = (index or 0) + 1
|
||||
if index <= #array then
|
||||
return index, array[index]
|
||||
end
|
||||
end
|
||||
function ipairsForArray(array)
|
||||
return nextForArray, array, 0
|
||||
end
|
||||
|
||||
getmetatable('').__metatable = false
|
||||
getSafeMetatable = function(v)
|
||||
if type(v) ~= 'table' then error('getmetatable is allowed only for tables', 2) end
|
||||
return getmetatable(v)
|
||||
end
|
||||
)");
|
||||
|
||||
mSandboxEnv = sol::table(mSol, sol::create);
|
||||
mSandboxEnv["_VERSION"] = mSol["_VERSION"];
|
||||
for (const std::string& s : safeFunctions)
|
||||
{
|
||||
if (mSol[s] == sol::nil)
|
||||
throw std::logic_error("Lua function not found: " + s);
|
||||
mSandboxEnv[s] = mSol[s];
|
||||
}
|
||||
for (const std::string& s : safePackages)
|
||||
{
|
||||
if (mSol[s] == sol::nil)
|
||||
throw std::logic_error("Lua package not found: " + s);
|
||||
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(mSol[s]);
|
||||
}
|
||||
mSandboxEnv["getmetatable"] = mSol["getSafeMetatable"];
|
||||
mCommonPackages["os"] = mSandboxEnv["os"]
|
||||
= makeReadOnly(tableFromPairs<std::string_view, sol::function>({ { "date", mSol["os"]["date"] },
|
||||
{ "difftime", mSol["os"]["difftime"] }, { "time", mSol["os"]["time"] } }));
|
||||
mSandboxEnv = sol::table(sol, sol::create);
|
||||
mSandboxEnv["_VERSION"] = sol["_VERSION"];
|
||||
for (const std::string& s : safeFunctions)
|
||||
{
|
||||
if (sol[s] == sol::nil)
|
||||
throw std::logic_error("Lua function not found: " + s);
|
||||
mSandboxEnv[s] = sol[s];
|
||||
}
|
||||
for (const std::string& s : safePackages)
|
||||
{
|
||||
if (sol[s] == sol::nil)
|
||||
throw std::logic_error("Lua package not found: " + s);
|
||||
mCommonPackages[s] = mSandboxEnv[s] = makeReadOnly(sol[s]);
|
||||
}
|
||||
mSandboxEnv["getmetatable"] = sol["getSafeMetatable"];
|
||||
mCommonPackages["os"] = mSandboxEnv["os"]
|
||||
= makeReadOnly(tableFromPairs<std::string_view, sol::function>(sol,
|
||||
{ { "date", sol["os"]["date"] }, { "difftime", sol["os"]["difftime"] },
|
||||
{ "time", sol["os"]["time"] } }));
|
||||
});
|
||||
}
|
||||
|
||||
sol::table makeReadOnly(const sol::table& table, bool strictIndex)
|
||||
@ -340,6 +344,7 @@ namespace LuaUtil
|
||||
sol::protected_function_result LuaState::runInNewSandbox(const std::string& path, const std::string& namePrefix,
|
||||
const std::map<std::string, sol::object>& packages, const sol::object& hiddenData)
|
||||
{
|
||||
// TODO
|
||||
sol::protected_function script = loadScriptAndCache(path);
|
||||
|
||||
sol::environment env(mSol, sol::create, mSandboxEnv);
|
||||
@ -373,6 +378,7 @@ namespace LuaUtil
|
||||
|
||||
sol::environment LuaState::newInternalLibEnvironment()
|
||||
{
|
||||
// TODO
|
||||
sol::environment env(mSol, sol::create, mSandboxEnv);
|
||||
sol::table loaded(mSol, sol::create);
|
||||
for (const std::string& s : safePackages)
|
||||
|
@ -34,6 +34,36 @@ namespace LuaUtil
|
||||
bool mLogMemoryUsage = false;
|
||||
};
|
||||
|
||||
class LuaState;
|
||||
class LuaView
|
||||
{
|
||||
sol::state_view mSol;
|
||||
|
||||
LuaView(const LuaView&) = delete;
|
||||
|
||||
LuaView(lua_State* L)
|
||||
: mSol(L)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
friend class LuaState;
|
||||
// Returns underlying sol::state.
|
||||
sol::state_view& sol() { return mSol; }
|
||||
|
||||
// A shortcut to create a new Lua table.
|
||||
sol::table newTable() { return sol::table(mSol, sol::create); }
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
sol::table tableFromPairs(lua_State* L, std::initializer_list<std::pair<Key, Value>> list)
|
||||
{
|
||||
sol::table res(L, sol::create);
|
||||
for (const auto& [k, v] : list)
|
||||
res[k] = v;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Holds Lua state.
|
||||
// Provides additional features:
|
||||
// - Load scripts from the virtual filesystem;
|
||||
@ -54,26 +84,53 @@ namespace LuaUtil
|
||||
LuaState(const LuaState&) = delete;
|
||||
LuaState(LuaState&&) = delete;
|
||||
|
||||
// Returns underlying sol::state.
|
||||
sol::state_view& sol() { return mSol; }
|
||||
// Pushing to the stack from outside a Lua context crashes the engine if no memory can be allocated to grow the
|
||||
// stack
|
||||
template <class Lambda>
|
||||
[[nodiscard]] int invokeProtectedCall(Lambda&& f) const
|
||||
{
|
||||
if (!lua_checkstack(mSol.lua_state(), 2))
|
||||
return LUA_ERRMEM;
|
||||
lua_pushcfunction(mSol.lua_state(), [](lua_State* L) {
|
||||
void* f = lua_touserdata(L, 1);
|
||||
LuaView view(L);
|
||||
(*static_cast<Lambda*>(f))(view);
|
||||
return 0;
|
||||
});
|
||||
lua_pushlightuserdata(mSol.lua_state(), &f);
|
||||
return lua_pcall(mSol.lua_state(), 1, 0, 0);
|
||||
}
|
||||
|
||||
template <class Lambda>
|
||||
void protectedCall(Lambda&& f) const
|
||||
{
|
||||
int result = invokeProtectedCall(std::forward<Lambda>(f));
|
||||
switch (result)
|
||||
{
|
||||
case LUA_OK:
|
||||
break;
|
||||
case LUA_ERRMEM:
|
||||
throw std::runtime_error("Lua error: out of memory");
|
||||
case LUA_ERRRUN:
|
||||
{
|
||||
sol::optional<std::string> error = sol::stack::check_get<std::string>(mSol.lua_state());
|
||||
if (error)
|
||||
throw std::runtime_error(*error);
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
throw std::runtime_error("Lua error: " + std::to_string(result));
|
||||
}
|
||||
}
|
||||
|
||||
// Note that constructing a sol::state_view is only safe from a Lua context. Use protectedCall to get one
|
||||
lua_State* unsafeState() const { return mSol.lua_state(); }
|
||||
|
||||
// Can be used by a C++ function that is called from Lua to get the Lua traceback.
|
||||
// Makes no sense if called not from Lua code.
|
||||
// Note: It is a slow function, should be used for debug purposes only.
|
||||
std::string debugTraceback() { return mSol["debug"]["traceback"]().get<std::string>(); }
|
||||
|
||||
// A shortcut to create a new Lua table.
|
||||
sol::table newTable() { return sol::table(mSol, sol::create); }
|
||||
|
||||
template <typename Key, typename Value>
|
||||
sol::table tableFromPairs(std::initializer_list<std::pair<Key, Value>> list)
|
||||
{
|
||||
sol::table res(mSol, sol::create);
|
||||
for (const auto& [k, v] : list)
|
||||
res[k] = v;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Registers a package that will be available from every sandbox via `require(name)`.
|
||||
// The package can be either a sol::table with an API or a sol::function. If it is a function,
|
||||
// it will be evaluated (once per sandbox) the first time when requested. If the package
|
||||
|
@ -24,8 +24,10 @@ namespace LuaUtil
|
||||
{
|
||||
sInstanceCount++;
|
||||
registerEngineHandlers({ &mUpdateHandlers });
|
||||
mPublicInterfaces = sol::table(lua->sol(), sol::create);
|
||||
addPackage("openmw.interfaces", mPublicInterfaces);
|
||||
lua->protectedCall([&](LuaView& view) {
|
||||
mPublicInterfaces = sol::table(view.sol(), sol::create);
|
||||
addPackage("openmw.interfaces", mPublicInterfaces);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptsContainer::printError(int scriptId, std::string_view msg, const std::exception& e)
|
||||
@ -41,26 +43,31 @@ namespace LuaUtil
|
||||
bool ScriptsContainer::addCustomScript(int scriptId, std::string_view initData)
|
||||
{
|
||||
assert(mLua.getConfiguration().isCustomScript(scriptId));
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
bool ok = addScript(scriptId, onInit, onLoad);
|
||||
if (ok && onInit)
|
||||
callOnInit(scriptId, *onInit, initData);
|
||||
bool ok = false;
|
||||
mLua.protectedCall([&](LuaView& view) {
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
ok = addScript(view, scriptId, onInit, onLoad);
|
||||
if (ok && onInit)
|
||||
callOnInit(view, scriptId, *onInit, initData);
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ScriptsContainer::addAutoStartedScripts()
|
||||
{
|
||||
for (const auto& [scriptId, data] : mAutoStartScripts)
|
||||
{
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
bool ok = addScript(scriptId, onInit, onLoad);
|
||||
if (ok && onInit)
|
||||
callOnInit(scriptId, *onInit, data);
|
||||
}
|
||||
mLua.protectedCall([&](LuaView& view) {
|
||||
for (const auto& [scriptId, data] : mAutoStartScripts)
|
||||
{
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
bool ok = addScript(view, scriptId, onInit, onLoad);
|
||||
if (ok && onInit)
|
||||
callOnInit(view, scriptId, *onInit, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ScriptsContainer::addScript(
|
||||
int scriptId, std::optional<sol::function>& onInit, std::optional<sol::function>& onLoad)
|
||||
LuaView& view, int scriptId, std::optional<sol::function>& onInit, std::optional<sol::function>& onLoad)
|
||||
{
|
||||
assert(scriptId >= 0 && scriptId < static_cast<int>(mLua.getConfiguration().size()));
|
||||
if (mScripts.count(scriptId) != 0)
|
||||
@ -73,7 +80,7 @@ namespace LuaUtil
|
||||
debugName.push_back(']');
|
||||
|
||||
Script& script = mScripts[scriptId];
|
||||
script.mHiddenData = mLua.newTable();
|
||||
script.mHiddenData = view.newTable();
|
||||
script.mHiddenData[sScriptIdKey] = ScriptId{ this, scriptId };
|
||||
script.mHiddenData[sScriptDebugNameKey] = debugName;
|
||||
script.mPath = path;
|
||||
@ -298,32 +305,34 @@ namespace LuaUtil
|
||||
auto it = mEventHandlers.find(eventName);
|
||||
if (it == mEventHandlers.end())
|
||||
return;
|
||||
sol::object data;
|
||||
try
|
||||
{
|
||||
data = LuaUtil::deserialize(mLua.sol(), eventData, mSerializer);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << mNamePrefix << " can not parse eventData for '" << eventName << "': " << e.what();
|
||||
return;
|
||||
}
|
||||
EventHandlerList& list = it->second;
|
||||
for (int i = list.size() - 1; i >= 0; --i)
|
||||
{
|
||||
const Handler& h = list[i];
|
||||
mLua.protectedCall([&](LuaView& view) {
|
||||
sol::object data;
|
||||
try
|
||||
{
|
||||
sol::object res = LuaUtil::call({ this, h.mScriptId }, h.mFn, data);
|
||||
if (res.is<bool>() && !res.as<bool>())
|
||||
break; // Skip other handlers if 'false' was returned.
|
||||
data = LuaUtil::deserialize(view.sol(), eventData, mSerializer);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << mNamePrefix << "[" << scriptPath(h.mScriptId) << "] eventHandler[" << eventName
|
||||
<< "] failed. " << e.what();
|
||||
Log(Debug::Error) << mNamePrefix << " can not parse eventData for '" << eventName << "': " << e.what();
|
||||
return;
|
||||
}
|
||||
}
|
||||
EventHandlerList& list = it->second;
|
||||
for (int i = list.size() - 1; i >= 0; --i)
|
||||
{
|
||||
const Handler& h = list[i];
|
||||
try
|
||||
{
|
||||
sol::object res = LuaUtil::call({ this, h.mScriptId }, h.mFn, data);
|
||||
if (res.is<bool>() && !res.as<bool>())
|
||||
break; // Skip other handlers if 'false' was returned.
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << mNamePrefix << "[" << scriptPath(h.mScriptId) << "] eventHandler[" << eventName
|
||||
<< "] failed. " << e.what();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptsContainer::registerEngineHandlers(std::initializer_list<EngineHandlerList*> handlers)
|
||||
@ -332,11 +341,11 @@ namespace LuaUtil
|
||||
mEngineHandlers[h->mName] = h;
|
||||
}
|
||||
|
||||
void ScriptsContainer::callOnInit(int scriptId, const sol::function& onInit, std::string_view data)
|
||||
void ScriptsContainer::callOnInit(LuaView& view, int scriptId, const sol::function& onInit, std::string_view data)
|
||||
{
|
||||
try
|
||||
{
|
||||
LuaUtil::call({ this, scriptId }, onInit, deserialize(mLua.sol(), data, mSerializer));
|
||||
LuaUtil::call({ this, scriptId }, onInit, deserialize(view.sol(), data, mSerializer));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@ -418,57 +427,61 @@ namespace LuaUtil
|
||||
<< "]; this script is not allowed here";
|
||||
}
|
||||
|
||||
for (const auto& [scriptId, scriptInfo] : scripts)
|
||||
{
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
if (!addScript(scriptId, onInit, onLoad))
|
||||
continue;
|
||||
if (scriptInfo.mSavedData == nullptr)
|
||||
mLua.protectedCall([&](LuaView& view) {
|
||||
for (const auto& [scriptId, scriptInfo] : scripts)
|
||||
{
|
||||
if (onInit)
|
||||
callOnInit(scriptId, *onInit, scriptInfo.mInitData);
|
||||
continue;
|
||||
}
|
||||
if (onLoad)
|
||||
{
|
||||
try
|
||||
std::optional<sol::function> onInit, onLoad;
|
||||
if (!addScript(view, scriptId, onInit, onLoad))
|
||||
continue;
|
||||
if (scriptInfo.mSavedData == nullptr)
|
||||
{
|
||||
sol::object state = deserialize(mLua.sol(), scriptInfo.mSavedData->mData, mSavedDataDeserializer);
|
||||
sol::object initializationData = deserialize(mLua.sol(), scriptInfo.mInitData, mSerializer);
|
||||
LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData);
|
||||
if (onInit)
|
||||
callOnInit(view, scriptId, *onInit, scriptInfo.mInitData);
|
||||
continue;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
if (onLoad)
|
||||
{
|
||||
printError(scriptId, "onLoad failed", e);
|
||||
try
|
||||
{
|
||||
sol::object state
|
||||
= deserialize(view.sol(), scriptInfo.mSavedData->mData, mSavedDataDeserializer);
|
||||
sol::object initializationData = deserialize(view.sol(), scriptInfo.mInitData, mSerializer);
|
||||
LuaUtil::call({ this, scriptId }, *onLoad, state, initializationData);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printError(scriptId, "onLoad failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const ESM::LuaTimer& savedTimer : scriptInfo.mSavedData->mTimers)
|
||||
{
|
||||
Timer timer;
|
||||
timer.mCallback = savedTimer.mCallbackName;
|
||||
timer.mSerializable = true;
|
||||
timer.mScriptId = scriptId;
|
||||
timer.mTime = savedTimer.mTime;
|
||||
for (const ESM::LuaTimer& savedTimer : scriptInfo.mSavedData->mTimers)
|
||||
{
|
||||
Timer timer;
|
||||
timer.mCallback = savedTimer.mCallbackName;
|
||||
timer.mSerializable = true;
|
||||
timer.mScriptId = scriptId;
|
||||
timer.mTime = savedTimer.mTime;
|
||||
|
||||
try
|
||||
{
|
||||
timer.mArg = sol::main_object(
|
||||
deserialize(mLua.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer));
|
||||
// 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 savedTimer.mCallbackArgument.
|
||||
timer.mSerializedArg = serialize(timer.mArg, mSerializer);
|
||||
try
|
||||
{
|
||||
timer.mArg = sol::main_object(
|
||||
deserialize(view.sol(), savedTimer.mCallbackArgument, mSavedDataDeserializer));
|
||||
// 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
|
||||
// savedTimer.mCallbackArgument.
|
||||
timer.mSerializedArg = serialize(timer.mArg, mSerializer);
|
||||
|
||||
if (savedTimer.mType == TimerType::GAME_TIME)
|
||||
mGameTimersQueue.push_back(std::move(timer));
|
||||
else
|
||||
mSimulationTimersQueue.push_back(std::move(timer));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printError(scriptId, "can not load timer", e);
|
||||
if (savedTimer.mType == TimerType::GAME_TIME)
|
||||
mGameTimersQueue.push_back(std::move(timer));
|
||||
else
|
||||
mSimulationTimersQueue.push_back(std::move(timer));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printError(scriptId, "can not load timer", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::make_heap(mSimulationTimersQueue.begin(), mSimulationTimersQueue.end());
|
||||
std::make_heap(mGameTimersQueue.begin(), mGameTimersQueue.end());
|
||||
|
@ -232,14 +232,15 @@ namespace LuaUtil
|
||||
void addMemoryUsage(int scriptId, int64_t memoryDelta);
|
||||
|
||||
// Add to container without calling onInit/onLoad.
|
||||
bool addScript(int scriptId, std::optional<sol::function>& onInit, std::optional<sol::function>& onLoad);
|
||||
bool addScript(
|
||||
LuaView& view, int scriptId, std::optional<sol::function>& onInit, std::optional<sol::function>& onLoad);
|
||||
|
||||
// Returns script by id (throws an exception if doesn't exist)
|
||||
Script& getScript(int scriptId);
|
||||
|
||||
void printError(int scriptId, std::string_view msg, const std::exception& e);
|
||||
const std::string& scriptPath(int scriptId) const { return mLua.getConfiguration()[scriptId].mScriptPath; }
|
||||
void callOnInit(int scriptId, const sol::function& onInit, std::string_view data);
|
||||
void callOnInit(LuaView& view, int scriptId, const sol::function& onInit, std::string_view data);
|
||||
void callTimer(const Timer& t);
|
||||
void updateTimerQueue(std::vector<Timer>& timerQueue, double time);
|
||||
static void insertTimer(std::vector<Timer>& timerQueue, Timer&& t);
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "luastate.hpp"
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <>
|
||||
@ -17,13 +19,14 @@ namespace LuaUtil
|
||||
{
|
||||
LuaStorage::Value LuaStorage::Section::sEmpty;
|
||||
|
||||
void LuaStorage::registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res)
|
||||
void LuaStorage::registerLifeTime(LuaUtil::LuaView& view, sol::table& res)
|
||||
{
|
||||
res["LIFE_TIME"] = LuaUtil::makeStrictReadOnly(luaState.tableFromPairs<std::string_view, Section::LifeTime>({
|
||||
{ "Persistent", Section::LifeTime::Persistent },
|
||||
{ "GameSession", Section::LifeTime::GameSession },
|
||||
{ "Temporary", Section::LifeTime::Temporary },
|
||||
}));
|
||||
res["LIFE_TIME"] = LuaUtil::makeStrictReadOnly(tableFromPairs<std::string_view, Section::LifeTime>(view.sol(),
|
||||
{
|
||||
{ "Persistent", Section::LifeTime::Persistent },
|
||||
{ "GameSession", Section::LifeTime::GameSession },
|
||||
{ "Temporary", Section::LifeTime::Temporary },
|
||||
}));
|
||||
}
|
||||
|
||||
sol::object LuaStorage::Value::getCopy(lua_State* L) const
|
||||
@ -112,26 +115,26 @@ namespace LuaUtil
|
||||
runCallbacks(sol::nullopt);
|
||||
}
|
||||
|
||||
sol::table LuaStorage::Section::asTable()
|
||||
sol::table LuaStorage::Section::asTable(lua_State* L)
|
||||
{
|
||||
checkIfActive();
|
||||
sol::table res(mStorage->mLua, sol::create);
|
||||
sol::table res(L, sol::create);
|
||||
for (const auto& [k, v] : mValues)
|
||||
res[k] = v.getCopy(mStorage->mLua);
|
||||
res[k] = v.getCopy(L);
|
||||
return res;
|
||||
}
|
||||
|
||||
void LuaStorage::initLuaBindings(lua_State* L)
|
||||
void LuaStorage::initLuaBindings(LuaUtil::LuaView& view)
|
||||
{
|
||||
sol::state_view lua(L);
|
||||
sol::usertype<SectionView> sview = lua.new_usertype<SectionView>("Section");
|
||||
sol::usertype<SectionView> sview = view.sol().new_usertype<SectionView>("Section");
|
||||
sview["get"] = [](sol::this_state s, const SectionView& section, std::string_view key) {
|
||||
return section.mSection->get(key).getReadOnly(s);
|
||||
};
|
||||
sview["getCopy"] = [](sol::this_state s, const SectionView& section, std::string_view key) {
|
||||
return section.mSection->get(key).getCopy(s);
|
||||
};
|
||||
sview["asTable"] = [](const SectionView& section) { return section.mSection->asTable(); };
|
||||
sview["asTable"]
|
||||
= [](sol::this_state lua, const SectionView& section) { return section.mSection->asTable(lua); };
|
||||
sview["subscribe"] = [](const SectionView& section, const sol::table& callback) {
|
||||
std::vector<Callback>& callbacks
|
||||
= section.mForMenuScripts ? section.mSection->mMenuScriptsCallbacks : section.mSection->mCallbacks;
|
||||
@ -165,53 +168,57 @@ namespace LuaUtil
|
||||
};
|
||||
}
|
||||
|
||||
sol::table LuaStorage::initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage)
|
||||
sol::table LuaStorage::initGlobalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage)
|
||||
{
|
||||
sol::table res(luaState.sol(), sol::create);
|
||||
registerLifeTime(luaState, res);
|
||||
sol::table res(view.sol(), sol::create);
|
||||
registerLifeTime(view, res);
|
||||
|
||||
res["globalSection"]
|
||||
= [globalStorage](std::string_view section) { return globalStorage->getMutableSection(section); };
|
||||
res["allGlobalSections"] = [globalStorage]() { return globalStorage->getAllSections(); };
|
||||
res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) {
|
||||
return globalStorage->getMutableSection(lua, section);
|
||||
};
|
||||
res["allGlobalSections"] = [globalStorage](sol::this_state lua) { return globalStorage->getAllSections(lua); };
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
||||
sol::table LuaStorage::initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage)
|
||||
sol::table LuaStorage::initLocalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage)
|
||||
{
|
||||
sol::table res(luaState.sol(), sol::create);
|
||||
registerLifeTime(luaState, res);
|
||||
sol::table res(view.sol(), sol::create);
|
||||
registerLifeTime(view, res);
|
||||
|
||||
res["globalSection"]
|
||||
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
|
||||
res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) {
|
||||
return globalStorage->getReadOnlySection(lua, section);
|
||||
};
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
||||
sol::table LuaStorage::initPlayerPackage(
|
||||
LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage)
|
||||
LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage)
|
||||
{
|
||||
sol::table res(luaState.sol(), sol::create);
|
||||
registerLifeTime(luaState, res);
|
||||
sol::table res(view.sol(), sol::create);
|
||||
registerLifeTime(view, res);
|
||||
|
||||
res["globalSection"]
|
||||
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
|
||||
res["playerSection"]
|
||||
= [playerStorage](std::string_view section) { return playerStorage->getMutableSection(section); };
|
||||
res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); };
|
||||
res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) {
|
||||
return globalStorage->getReadOnlySection(lua, section);
|
||||
};
|
||||
res["playerSection"] = [playerStorage](sol::this_state lua, std::string_view section) {
|
||||
return playerStorage->getMutableSection(lua, section);
|
||||
};
|
||||
res["allPlayerSections"] = [playerStorage](sol::this_state lua) { return playerStorage->getAllSections(lua); };
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
||||
sol::table LuaStorage::initMenuPackage(
|
||||
LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage)
|
||||
sol::table LuaStorage::initMenuPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage)
|
||||
{
|
||||
sol::table res(luaState.sol(), sol::create);
|
||||
registerLifeTime(luaState, res);
|
||||
sol::table res(view.sol(), sol::create);
|
||||
registerLifeTime(view, res);
|
||||
|
||||
res["playerSection"] = [playerStorage](std::string_view section) {
|
||||
return playerStorage->getMutableSection(section, /*forMenuScripts=*/true);
|
||||
res["playerSection"] = [playerStorage](sol::this_state lua, std::string_view section) {
|
||||
return playerStorage->getMutableSection(lua, section, /*forMenuScripts=*/true);
|
||||
};
|
||||
res["globalSection"]
|
||||
= [globalStorage](std::string_view section) { return globalStorage->getReadOnlySection(section); };
|
||||
res["allPlayerSections"] = [playerStorage]() { return playerStorage->getAllSections(); };
|
||||
res["globalSection"] = [globalStorage](sol::this_state lua, std::string_view section) {
|
||||
return globalStorage->getReadOnlySection(lua, section);
|
||||
};
|
||||
res["allPlayerSections"] = [playerStorage](sol::this_state lua) { return playerStorage->getAllSections(lua); };
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
|
||||
@ -234,7 +241,7 @@ namespace LuaUtil
|
||||
}
|
||||
}
|
||||
|
||||
void LuaStorage::load(const std::filesystem::path& path)
|
||||
void LuaStorage::load(lua_State* L, const std::filesystem::path& path)
|
||||
{
|
||||
assert(mData.empty()); // Shouldn't be used before loading
|
||||
try
|
||||
@ -246,7 +253,7 @@ namespace LuaUtil
|
||||
|
||||
std::ifstream fin(path, std::fstream::binary);
|
||||
std::string serializedData((std::istreambuf_iterator<char>(fin)), std::istreambuf_iterator<char>());
|
||||
sol::table data = deserialize(mLua, serializedData);
|
||||
sol::table data = deserialize(L, serializedData);
|
||||
for (const auto& [sectionName, sectionTable] : data)
|
||||
{
|
||||
const std::shared_ptr<Section>& section = getSection(cast<std::string_view>(sectionName));
|
||||
@ -260,13 +267,13 @@ namespace LuaUtil
|
||||
}
|
||||
}
|
||||
|
||||
void LuaStorage::save(const std::filesystem::path& path) const
|
||||
void LuaStorage::save(lua_State* L, const std::filesystem::path& path) const
|
||||
{
|
||||
sol::table data(mLua, sol::create);
|
||||
sol::table data(L, sol::create);
|
||||
for (const auto& [sectionName, section] : mData)
|
||||
{
|
||||
if (section->mLifeTime == Section::Persistent && !section->mValues.empty())
|
||||
data[sectionName] = section->asTable();
|
||||
data[sectionName] = section->asTable(L);
|
||||
}
|
||||
std::string serializedData = serialize(data);
|
||||
Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)";
|
||||
@ -287,19 +294,19 @@ namespace LuaUtil
|
||||
return newIt->second;
|
||||
}
|
||||
|
||||
sol::object LuaStorage::getSection(std::string_view sectionName, bool readOnly, bool forMenuScripts)
|
||||
sol::object LuaStorage::getSection(lua_State* L, std::string_view sectionName, bool readOnly, bool forMenuScripts)
|
||||
{
|
||||
checkIfActive();
|
||||
const std::shared_ptr<Section>& section = getSection(sectionName);
|
||||
return sol::make_object<SectionView>(mLua, SectionView{ section, readOnly, forMenuScripts });
|
||||
return sol::make_object<SectionView>(L, SectionView{ section, readOnly, forMenuScripts });
|
||||
}
|
||||
|
||||
sol::table LuaStorage::getAllSections(bool readOnly)
|
||||
sol::table LuaStorage::getAllSections(lua_State* L, bool readOnly)
|
||||
{
|
||||
checkIfActive();
|
||||
sol::table res(mLua, sol::create);
|
||||
sol::table res(L, sol::create);
|
||||
for (const auto& [sectionName, _] : mData)
|
||||
res[sectionName] = getSection(sectionName, readOnly);
|
||||
res[sectionName] = getSection(L, sectionName, readOnly);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -10,35 +10,34 @@
|
||||
|
||||
namespace LuaUtil
|
||||
{
|
||||
class LuaView;
|
||||
|
||||
class LuaStorage
|
||||
{
|
||||
public:
|
||||
static void initLuaBindings(lua_State* L);
|
||||
static sol::table initGlobalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage);
|
||||
static sol::table initLocalPackage(LuaUtil::LuaState& luaState, LuaStorage* globalStorage);
|
||||
static void initLuaBindings(LuaUtil::LuaView& view);
|
||||
static sol::table initGlobalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage);
|
||||
static sol::table initLocalPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage);
|
||||
static sol::table initPlayerPackage(
|
||||
LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage);
|
||||
static sol::table initMenuPackage(
|
||||
LuaUtil::LuaState& luaState, LuaStorage* globalStorage, LuaStorage* playerStorage);
|
||||
LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage);
|
||||
static sol::table initMenuPackage(LuaUtil::LuaView& view, LuaStorage* globalStorage, LuaStorage* playerStorage);
|
||||
|
||||
explicit LuaStorage(lua_State* lua)
|
||||
: mLua(lua)
|
||||
, mActive(false)
|
||||
{
|
||||
}
|
||||
explicit LuaStorage() {}
|
||||
|
||||
void clearTemporaryAndRemoveCallbacks();
|
||||
void load(const std::filesystem::path& path);
|
||||
void save(const std::filesystem::path& path) const;
|
||||
void load(lua_State* L, const std::filesystem::path& path);
|
||||
void save(lua_State* L, const std::filesystem::path& path) const;
|
||||
|
||||
sol::object getSection(std::string_view sectionName, bool readOnly, bool forMenuScripts = false);
|
||||
sol::object getMutableSection(std::string_view sectionName, bool forMenuScripts = false)
|
||||
sol::object getSection(lua_State* L, std::string_view sectionName, bool readOnly, bool forMenuScripts = false);
|
||||
sol::object getMutableSection(lua_State* L, std::string_view sectionName, bool forMenuScripts = false)
|
||||
{
|
||||
return getSection(sectionName, false, forMenuScripts);
|
||||
return getSection(L, sectionName, false, forMenuScripts);
|
||||
}
|
||||
sol::object getReadOnlySection(std::string_view sectionName) { return getSection(sectionName, true); }
|
||||
sol::table getAllSections(bool readOnly = false);
|
||||
sol::object getReadOnlySection(lua_State* L, std::string_view sectionName)
|
||||
{
|
||||
return getSection(L, sectionName, true);
|
||||
}
|
||||
sol::table getAllSections(lua_State* L, bool readOnly = false);
|
||||
|
||||
void setSingleValue(std::string_view section, std::string_view key, const sol::object& value)
|
||||
{
|
||||
@ -95,7 +94,7 @@ namespace LuaUtil
|
||||
const Value& get(std::string_view key) const;
|
||||
void set(std::string_view key, const sol::object& value);
|
||||
void setAll(const sol::optional<sol::table>& values);
|
||||
sol::table asTable();
|
||||
sol::table asTable(lua_State* L);
|
||||
void runCallbacks(sol::optional<std::string_view> changedKey);
|
||||
void throwIfCallbackRecursionIsTooDeep();
|
||||
|
||||
@ -119,17 +118,16 @@ namespace LuaUtil
|
||||
|
||||
const std::shared_ptr<Section>& getSection(std::string_view sectionName);
|
||||
|
||||
lua_State* mLua;
|
||||
std::map<std::string_view, std::shared_ptr<Section>> mData;
|
||||
const Listener* mListener = nullptr;
|
||||
std::set<const Section*> mRunningCallbacks;
|
||||
bool mActive;
|
||||
bool mActive = false;
|
||||
void checkIfActive() const
|
||||
{
|
||||
if (!mActive)
|
||||
throw std::logic_error("Trying to access inactive storage");
|
||||
}
|
||||
static void registerLifeTime(LuaUtil::LuaState& luaState, sol::table& res);
|
||||
static void registerLifeTime(LuaUtil::LuaView& view, sol::table& res);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user