mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-24 04:11:50 -04:00
more generic + cell cache
This commit is contained in:
parent
d66be6ac70
commit
99ecdf74b3
@ -4,62 +4,81 @@ namespace MWLua
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr std::string_view REG_KEY = "LUA_GAMEOBJECTS_REGISTRY";
|
||||
template <typename T>
|
||||
inline constexpr bool is_gameObject = std::is_same_v<LObject, T> || std::is_same_v<GObject, T>;
|
||||
template <typename T>
|
||||
inline constexpr bool is_cell = std::is_same_v<LCell, T> || std::is_same_v<GCell, T>;
|
||||
|
||||
inline int64_t toInt64(const ObjectId& id)
|
||||
constexpr std::string_view gameObjects = "LUA_GAMEOBJECTS_REGISTRY";
|
||||
constexpr std::string_view cells = "LUA_CELLS_REGISTRY";
|
||||
|
||||
inline constexpr uint64_t toUInt64(const ObjectId& id)
|
||||
{
|
||||
if (id.hasContentFile())
|
||||
return static_cast<int64_t>(id.mIndex) | (static_cast<int64_t>(id.mContentFile) << 32);
|
||||
return id.mIndex | (static_cast<uint64_t>(id.mContentFile) << 24);
|
||||
else
|
||||
return static_cast<int64_t>(id.mIndex) | (static_cast<int64_t>(-id.mContentFile - 1) << 32);
|
||||
return id.mIndex | (static_cast<uint64_t>(-id.mContentFile - 1) << 32);
|
||||
}
|
||||
|
||||
inline sol::table getRegistry(sol::state_view lua)
|
||||
inline sol::table getRegistry(std::string_view key, sol::state_view lua)
|
||||
{
|
||||
if (sol::object reg = lua.registry()[REG_KEY]; reg.valid()) // LUA_REGISTRYINDEX
|
||||
if (sol::object reg = lua.registry()[key]; reg.valid()) // LUA_REGISTRYINDEX
|
||||
return reg.as<sol::table>();
|
||||
|
||||
sol::table t(lua, sol::create);
|
||||
t[sol::metatable_key] = lua.create_table_with("__mode", "v"); // weak table
|
||||
|
||||
lua.registry()[REG_KEY] = t;
|
||||
lua.registry()[key] = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename Obj, typename PtrOrId>
|
||||
sol::object makeOrGetImpl(PtrOrId input, sol::state_view lua)
|
||||
template <typename userT, typename ArgT>
|
||||
sol::object makeOrGetImpl(ArgT arg, sol::state_view lua)
|
||||
{
|
||||
static_assert(std::is_constructible_v<Obj, PtrOrId>);
|
||||
static_assert(std::is_constructible_v<userT, ArgT>);
|
||||
|
||||
ObjectId id;
|
||||
if constexpr (std::is_same_v<PtrOrId, MWWorld::Ptr>)
|
||||
id = getId(input);
|
||||
else
|
||||
id = input;
|
||||
sol::table registry;
|
||||
sol::object key;
|
||||
|
||||
if constexpr (is_gameObject<userT>)
|
||||
{
|
||||
registry = getRegistry(gameObjects, lua);
|
||||
if constexpr (std::is_same_v<ArgT, MWWorld::Ptr>)
|
||||
key = sol::make_object(lua, toUInt64(getId(arg)));
|
||||
else
|
||||
key = sol::make_object(lua, toUInt64(arg));
|
||||
}
|
||||
else if constexpr (is_cell<userT>)
|
||||
{
|
||||
registry = getRegistry(cells, lua);
|
||||
key = sol::make_object(lua, sol::make_light(arg));
|
||||
}
|
||||
// else compile error
|
||||
|
||||
int64_t key = toInt64(id);
|
||||
sol::table registry = getRegistry(lua);
|
||||
sol::object existing = registry[key];
|
||||
|
||||
if (existing.valid())
|
||||
return existing;
|
||||
|
||||
sol::object obj = sol::make_object(lua, Obj(input));
|
||||
sol::object obj = sol::make_object(lua, userT(arg));
|
||||
registry[key] = obj; // stored in weak table so garbage collector should work on this
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename Obj, typename ptrOrId>
|
||||
sol::object makeOrGet(ptrOrId input, sol::state_view lua)
|
||||
template <typename userT, typename ArgT>
|
||||
sol::object makeOrGet(ArgT arg, sol::state_view lua)
|
||||
{
|
||||
return makeOrGetImpl<Obj>(input, lua);
|
||||
return makeOrGetImpl<userT>(arg, lua);
|
||||
}
|
||||
|
||||
// Game Objects
|
||||
template sol::object MWLua::makeOrGet<LObject, MWWorld::Ptr>(MWWorld::Ptr, sol::state_view);
|
||||
template sol::object MWLua::makeOrGet<LObject, ObjectId>(ObjectId, sol::state_view);
|
||||
template sol::object MWLua::makeOrGet<GObject, MWWorld::Ptr>(MWWorld::Ptr, sol::state_view);
|
||||
template sol::object MWLua::makeOrGet<GObject, ObjectId>(ObjectId, sol::state_view);
|
||||
|
||||
// Cells
|
||||
template sol::object MWLua::makeOrGet<LCell, MWWorld::CellStore*>(MWWorld::CellStore*, sol::state_view);
|
||||
template sol::object MWLua::makeOrGet<GCell, MWWorld::CellStore*>(MWWorld::CellStore*, sol::state_view);
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ namespace MWLua
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Obj, typename ptrOrId>
|
||||
sol::object makeOrGet(ptrOrId input, sol::state_view lua);
|
||||
template <typename userT, typename ArgT>
|
||||
sol::object makeOrGet(ArgT arg, sol::state_view lua);
|
||||
|
||||
// Used only in local scripts
|
||||
struct LCell
|
||||
|
@ -278,6 +278,7 @@ namespace MWLua
|
||||
template <class ObjectT>
|
||||
void addBasicBindings(sol::usertype<ObjectT>& objectT, const Context& context)
|
||||
{
|
||||
sol::state_view lua = context.sol();
|
||||
objectT["id"] = sol::readonly_property([](const ObjectT& o) -> std::string { return o.id().toString(); });
|
||||
objectT["contentFile"] = sol::readonly_property([](const ObjectT& o) -> sol::optional<std::string> {
|
||||
int contentFileIndex = o.id().mContentFile;
|
||||
@ -296,13 +297,13 @@ namespace MWLua
|
||||
else
|
||||
return ESM::RefId::stringRefId(globalVariable).serializeText();
|
||||
});
|
||||
objectT["cell"] = sol::readonly_property([](const ObjectT& o) -> sol::optional<Cell<ObjectT>> {
|
||||
objectT["cell"] = sol::readonly_property([lua](const ObjectT& o) -> sol::object {
|
||||
const MWWorld::Ptr& ptr = o.ptr();
|
||||
MWWorld::WorldModel* wm = MWBase::Environment::get().getWorldModel();
|
||||
if (ptr.isInCell() && ptr.getCell() != &wm->getDraftCell())
|
||||
return Cell<ObjectT>{ ptr.getCell() };
|
||||
return makeOrGet<Cell<ObjectT>>(ptr.getCell(), lua);
|
||||
else
|
||||
return sol::nullopt;
|
||||
return sol::nil;
|
||||
});
|
||||
objectT["parentContainer"] = sol::readonly_property([](const ObjectT& o) -> sol::optional<ObjectT> {
|
||||
const MWWorld::Ptr& ptr = o.ptr();
|
||||
|
@ -96,9 +96,9 @@ namespace MWLua
|
||||
return sol::nil;
|
||||
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||
if (dynamic_cast<const GObject*>(&o))
|
||||
return sol::make_object(thisState, GCell{ &cell });
|
||||
return makeOrGet<GCell>(&cell, thisState);
|
||||
else
|
||||
return sol::make_object(thisState, LCell{ &cell });
|
||||
return makeOrGet<LCell>(&cell, thisState);
|
||||
};
|
||||
|
||||
addRecordFunctionBinding<ESM::Door>(door, context);
|
||||
@ -132,9 +132,9 @@ namespace MWLua
|
||||
return sol::nil;
|
||||
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||
if (dynamic_cast<const GObject*>(&o))
|
||||
return sol::make_object(lua, GCell{ &cell });
|
||||
return makeOrGet<GCell>(&cell, lua);
|
||||
else
|
||||
return sol::make_object(lua, LCell{ &cell });
|
||||
return makeOrGet<LCell>(&cell, lua);
|
||||
};
|
||||
|
||||
addRecordFunctionBinding<ESM4::Door>(door, context, "ESM4Door");
|
||||
|
@ -81,14 +81,16 @@ namespace MWLua
|
||||
|
||||
static void addCellGetters(sol::table& api, const Context& context)
|
||||
{
|
||||
api["getCellByName"] = [](std::string_view name) {
|
||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name, /*forceLoad=*/false) };
|
||||
sol::state_view lua = context.sol();
|
||||
api["getCellByName"] = [lua](std::string_view name) {
|
||||
return makeOrGet<GCell>(
|
||||
&MWBase::Environment::get().getWorldModel()->getCell(name, /*forceLoad=*/false), lua);
|
||||
};
|
||||
api["getCellById"] = [](std::string_view stringId) {
|
||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(
|
||||
ESM::RefId::deserializeText(stringId), /*forceLoad=*/false) };
|
||||
api["getCellById"] = [lua](std::string_view stringId) {
|
||||
ESM::RefId id = ESM::RefId::deserializeText(stringId);
|
||||
return makeOrGet<GCell>(&MWBase::Environment::get().getWorldModel()->getCell(id, /*forceLoad=*/false), lua);
|
||||
};
|
||||
api["getExteriorCell"] = [](int x, int y, sol::object cellOrName) {
|
||||
api["getExteriorCell"] = [lua](int x, int y, sol::object cellOrName) {
|
||||
ESM::RefId worldspace;
|
||||
if (cellOrName.is<GCell>())
|
||||
worldspace = cellOrName.as<GCell>().mStore->getCell()->getWorldSpace();
|
||||
@ -100,8 +102,9 @@ namespace MWLua
|
||||
->getWorldSpace();
|
||||
else
|
||||
worldspace = ESM::Cell::sDefaultWorldspaceId;
|
||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior(
|
||||
ESM::ExteriorCellLocation(x, y, worldspace), /*forceLoad=*/false) };
|
||||
auto location = ESM::ExteriorCellLocation(x, y, worldspace);
|
||||
return makeOrGet<GCell>(
|
||||
&MWBase::Environment::get().getWorldModel()->getExterior(location, /*forceLoad=*/false), lua);
|
||||
};
|
||||
|
||||
const MWWorld::Store<ESM::Cell>* cells3Store = &MWBase::Environment::get().getESMStore()->get<ESM::Cell>();
|
||||
@ -111,22 +114,22 @@ namespace MWLua
|
||||
cells[sol::meta_function::length]
|
||||
= [cells3Store, cells4Store](const CellsStore&) { return cells3Store->getSize() + cells4Store->getSize(); };
|
||||
cells[sol::meta_function::index]
|
||||
= [cells3Store, cells4Store](const CellsStore&, size_t index) -> sol::optional<GCell> {
|
||||
= [cells3Store, cells4Store, lua](const CellsStore&, size_t index) -> sol::object {
|
||||
if (index > cells3Store->getSize() + cells3Store->getSize() || index == 0)
|
||||
return sol::nullopt;
|
||||
return sol::nil;
|
||||
|
||||
index--; // Translate from Lua's 1-based indexing.
|
||||
if (index < cells3Store->getSize())
|
||||
{
|
||||
const ESM::Cell* cellRecord = cells3Store->at(index);
|
||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(
|
||||
cellRecord->mId, /*forceLoad=*/false) };
|
||||
return makeOrGet<GCell>(
|
||||
&MWBase::Environment::get().getWorldModel()->getCell(cellRecord->mId, /*forceLoad=*/false), lua);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ESM4::Cell* cellRecord = cells4Store->at(index - cells3Store->getSize());
|
||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(
|
||||
cellRecord->mId, /*forceLoad=*/false) };
|
||||
return makeOrGet<GCell>(
|
||||
&MWBase::Environment::get().getWorldModel()->getCell(cellRecord->mId, /*forceLoad=*/false), lua);
|
||||
}
|
||||
};
|
||||
cells[sol::meta_function::pairs] = view["ipairsForArray"].template get<sol::function>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user