mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Merge branch 'localpairs' into 'master'
Allow mwscript variable iteration See merge request OpenMW/openmw!4180
This commit is contained in:
commit
8471cfb576
5 changed files with 129 additions and 12 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "mwscriptbindings.hpp"
|
#include "mwscriptbindings.hpp"
|
||||||
|
|
||||||
|
#include <components/compiler/locals.hpp>
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
#include <components/lua/util.hpp>
|
#include <components/lua/util.hpp>
|
||||||
#include <components/misc/strings/lower.hpp>
|
#include <components/misc/strings/lower.hpp>
|
||||||
|
@ -94,18 +95,75 @@ namespace MWLua
|
||||||
});
|
});
|
||||||
mwscript["player"] = sol::readonly_property(
|
mwscript["player"] = sol::readonly_property(
|
||||||
[](const MWScriptRef&) { return GObject(MWBase::Environment::get().getWorld()->getPlayerPtr()); });
|
[](const MWScriptRef&) { return GObject(MWBase::Environment::get().getWorld()->getPlayerPtr()); });
|
||||||
mwscriptVars[sol::meta_function::index]
|
mwscriptVars[sol::meta_function::length]
|
||||||
= [](MWScriptVariables& s, std::string_view var) -> sol::optional<double> {
|
= [](MWScriptVariables& s) { return s.mRef.getLocals().getSize(s.mRef.mId); };
|
||||||
if (s.mRef.getLocals().hasVar(s.mRef.mId, var))
|
mwscriptVars[sol::meta_function::index] = sol::overload(
|
||||||
return s.mRef.getLocals().getVarAsDouble(s.mRef.mId, Misc::StringUtils::lowerCase(var));
|
[](MWScriptVariables& s, std::string_view var) -> sol::optional<double> {
|
||||||
else
|
if (s.mRef.getLocals().hasVar(s.mRef.mId, var))
|
||||||
|
return s.mRef.getLocals().getVarAsDouble(s.mRef.mId, Misc::StringUtils::lowerCase(var));
|
||||||
|
else
|
||||||
|
return sol::nullopt;
|
||||||
|
},
|
||||||
|
[](MWScriptVariables& s, std::size_t index) -> sol::optional<double> {
|
||||||
|
auto& locals = s.mRef.getLocals();
|
||||||
|
if (index < 1 || locals.getSize(s.mRef.mId) < index)
|
||||||
|
return sol::nullopt;
|
||||||
|
if (index <= locals.mShorts.size())
|
||||||
|
return locals.mShorts[index - 1];
|
||||||
|
index -= locals.mShorts.size();
|
||||||
|
if (index <= locals.mLongs.size())
|
||||||
|
return locals.mLongs[index - 1];
|
||||||
|
index -= locals.mLongs.size();
|
||||||
|
if (index <= locals.mFloats.size())
|
||||||
|
return locals.mFloats[index - 1];
|
||||||
return sol::nullopt;
|
return sol::nullopt;
|
||||||
};
|
});
|
||||||
mwscriptVars[sol::meta_function::new_index] = [](MWScriptVariables& s, std::string_view var, double val) {
|
mwscriptVars[sol::meta_function::new_index] = sol::overload(
|
||||||
MWScript::Locals& locals = s.mRef.getLocals();
|
[](MWScriptVariables& s, std::string_view var, double val) {
|
||||||
if (!locals.setVar(s.mRef.mId, Misc::StringUtils::lowerCase(var), val))
|
MWScript::Locals& locals = s.mRef.getLocals();
|
||||||
throw std::runtime_error(
|
if (!locals.setVar(s.mRef.mId, Misc::StringUtils::lowerCase(var), val))
|
||||||
"No variable \"" + std::string(var) + "\" in mwscript " + s.mRef.mId.toDebugString());
|
throw std::runtime_error(
|
||||||
|
"No variable \"" + std::string(var) + "\" in mwscript " + s.mRef.mId.toDebugString());
|
||||||
|
},
|
||||||
|
[](MWScriptVariables& s, std::size_t index, double val) {
|
||||||
|
auto& locals = s.mRef.getLocals();
|
||||||
|
if (index < 1 || locals.getSize(s.mRef.mId) < index)
|
||||||
|
throw std::runtime_error("Index out of range in mwscript " + s.mRef.mId.toDebugString());
|
||||||
|
if (index <= locals.mShorts.size())
|
||||||
|
{
|
||||||
|
locals.mShorts[index - 1] = static_cast<Interpreter::Type_Short>(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index -= locals.mShorts.size();
|
||||||
|
if (index <= locals.mLongs.size())
|
||||||
|
{
|
||||||
|
locals.mLongs[index - 1] = static_cast<Interpreter::Type_Integer>(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index -= locals.mLongs.size();
|
||||||
|
if (index <= locals.mFloats.size())
|
||||||
|
locals.mFloats[index - 1] = static_cast<Interpreter::Type_Float>(val);
|
||||||
|
});
|
||||||
|
mwscriptVars[sol::meta_function::pairs] = [](MWScriptVariables& s) {
|
||||||
|
std::size_t index = 0;
|
||||||
|
const auto& compilerLocals = MWBase::Environment::get().getScriptManager()->getLocals(s.mRef.mId);
|
||||||
|
auto& locals = s.mRef.getLocals();
|
||||||
|
std::size_t size = locals.getSize(s.mRef.mId);
|
||||||
|
return sol::as_function(
|
||||||
|
[&, index, size](sol::this_state ts) mutable -> sol::optional<std::tuple<std::string_view, double>> {
|
||||||
|
if (index >= size)
|
||||||
|
return sol::nullopt;
|
||||||
|
auto i = index++;
|
||||||
|
if (i < locals.mShorts.size())
|
||||||
|
return std::make_tuple<std::string_view, double>(compilerLocals.get('s')[i], locals.mShorts[i]);
|
||||||
|
i -= locals.mShorts.size();
|
||||||
|
if (i < locals.mLongs.size())
|
||||||
|
return std::make_tuple<std::string_view, double>(compilerLocals.get('l')[i], locals.mLongs[i]);
|
||||||
|
i -= locals.mLongs.size();
|
||||||
|
if (i < locals.mFloats.size())
|
||||||
|
return std::make_tuple<std::string_view, double>(compilerLocals.get('f')[i], locals.mFloats[i]);
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
using GlobalStore = MWWorld::Store<ESM::Global>;
|
using GlobalStore = MWWorld::Store<ESM::Global>;
|
||||||
|
@ -173,5 +231,4 @@ namespace MWLua
|
||||||
};
|
};
|
||||||
return LuaUtil::makeReadOnly(api);
|
return LuaUtil::makeReadOnly(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,12 @@ namespace MWScript
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t Locals::getSize(const ESM::RefId& script)
|
||||||
|
{
|
||||||
|
ensure(script);
|
||||||
|
return mShorts.size() + mLongs.size() + mFloats.size();
|
||||||
|
}
|
||||||
|
|
||||||
bool Locals::write(ESM::Locals& locals, const ESM::RefId& script) const
|
bool Locals::write(ESM::Locals& locals, const ESM::RefId& script) const
|
||||||
{
|
{
|
||||||
if (!mInitialised)
|
if (!mInitialised)
|
||||||
|
|
|
@ -67,6 +67,8 @@ namespace MWScript
|
||||||
return static_cast<float>(getVarAsDouble(script, var));
|
return static_cast<float>(getVarAsDouble(script, var));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t getSize(const ESM::RefId& script);
|
||||||
|
|
||||||
/// \note If locals have not been configured yet, no data is written.
|
/// \note If locals have not been configured yet, no data is written.
|
||||||
///
|
///
|
||||||
/// \return Locals written?
|
/// \return Locals written?
|
||||||
|
|
|
@ -24,6 +24,7 @@ end
|
||||||
local testModules = {
|
local testModules = {
|
||||||
'global_issues',
|
'global_issues',
|
||||||
'global_dialogues',
|
'global_dialogues',
|
||||||
|
'global_mwscript',
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
51
scripts/data/morrowind_tests/global_mwscript.lua
Normal file
51
scripts/data/morrowind_tests/global_mwscript.lua
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
local testing = require('testing_util')
|
||||||
|
local core = require('openmw.core')
|
||||||
|
local world = require('openmw.world')
|
||||||
|
|
||||||
|
function iterateOverVariables(variables)
|
||||||
|
local first = nil
|
||||||
|
local last = nil
|
||||||
|
local count = 0
|
||||||
|
for k, _ in pairs(variables) do
|
||||||
|
first = first or k
|
||||||
|
last = k
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
return first, last, count
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
{'Should support iteration over an empty set of script variables', function()
|
||||||
|
local mainVars = world.mwscript.getGlobalScript('main').variables
|
||||||
|
local first, last, count = iterateOverVariables(mainVars)
|
||||||
|
testing.expectEqual(first, nil)
|
||||||
|
testing.expectEqual(last, nil)
|
||||||
|
testing.expectEqual(count, 0)
|
||||||
|
testing.expectEqual(count, #mainVars)
|
||||||
|
end},
|
||||||
|
{'Should support iteration of script variables', function()
|
||||||
|
local jiub = world.getObjectByFormId(core.getFormId('Morrowind.esm', 172867))
|
||||||
|
local jiubVars = world.mwscript.getLocalScript(jiub).variables
|
||||||
|
local first, last, count = iterateOverVariables(jiubVars)
|
||||||
|
|
||||||
|
testing.expectEqual(first, 'state')
|
||||||
|
testing.expectEqual(last, 'timer')
|
||||||
|
testing.expectEqual(count, 3)
|
||||||
|
testing.expectEqual(count, #jiubVars)
|
||||||
|
end},
|
||||||
|
{'Should support numeric and string indices for getting and setting', function()
|
||||||
|
local jiub = world.getObjectByFormId(core.getFormId('Morrowind.esm', 172867))
|
||||||
|
local jiubVars = world.mwscript.getLocalScript(jiub).variables
|
||||||
|
|
||||||
|
testing.expectEqual(jiubVars[1], jiubVars.state)
|
||||||
|
testing.expectEqual(jiubVars[2], jiubVars.wandering)
|
||||||
|
testing.expectEqual(jiubVars[3], jiubVars.timer)
|
||||||
|
|
||||||
|
jiubVars[1] = 123;
|
||||||
|
testing.expectEqual(jiubVars.state, 123)
|
||||||
|
jiubVars.wandering = 42;
|
||||||
|
testing.expectEqual(jiubVars[2], 42)
|
||||||
|
jiubVars[3] = 1.25;
|
||||||
|
testing.expectEqual(jiubVars.timer, 1.25)
|
||||||
|
end},
|
||||||
|
}
|
Loading…
Reference in a new issue