mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-23 09:26:37 +00:00
Additional Lua bindings for cells
This commit is contained in:
parent
2725a9d7f4
commit
ce7f6f31c9
7 changed files with 105 additions and 25 deletions
|
@ -33,7 +33,8 @@ namespace MWLua
|
||||||
auto cell = c.mStore->getCell();
|
auto cell = c.mStore->getCell();
|
||||||
std::stringstream res;
|
std::stringstream res;
|
||||||
if (cell->isExterior())
|
if (cell->isExterior())
|
||||||
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")";
|
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ", "
|
||||||
|
<< cell->getWorldSpace().toDebugString() << ")";
|
||||||
else
|
else
|
||||||
res << "interior(" << cell->getNameId() << ")";
|
res << "interior(" << cell->getNameId() << ")";
|
||||||
return res.str();
|
return res.str();
|
||||||
|
@ -42,6 +43,8 @@ namespace MWLua
|
||||||
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); });
|
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); });
|
||||||
cellT["region"] = sol::readonly_property(
|
cellT["region"] = sol::readonly_property(
|
||||||
[](const CellT& c) -> std::string { return c.mStore->getCell()->getRegion().serializeText(); });
|
[](const CellT& c) -> std::string { return c.mStore->getCell()->getRegion().serializeText(); });
|
||||||
|
cellT["worldSpaceId"] = sol::readonly_property(
|
||||||
|
[](const CellT& c) -> std::string { return c.mStore->getCell()->getWorldSpace().serializeText(); });
|
||||||
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
|
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
|
||||||
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
|
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
|
||||||
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
|
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
|
||||||
|
@ -67,13 +70,15 @@ namespace MWLua
|
||||||
if (!ptr.isInCell())
|
if (!ptr.isInCell())
|
||||||
return false;
|
return false;
|
||||||
MWWorld::CellStore* cell = ptr.getCell();
|
MWWorld::CellStore* cell = ptr.getCell();
|
||||||
return cell == c.mStore || (cell->isExterior() && c.mStore->isExterior());
|
return cell == c.mStore || (cell->getCell()->getWorldSpace() == c.mStore->getCell()->getWorldSpace());
|
||||||
};
|
};
|
||||||
|
|
||||||
if constexpr (std::is_same_v<CellT, GCell>)
|
if constexpr (std::is_same_v<CellT, GCell>)
|
||||||
{ // only for global scripts
|
{ // only for global scripts
|
||||||
cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
|
cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
|
||||||
const CellT& cell, sol::optional<sol::table> type) {
|
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>>();
|
ObjectIdList res = std::make_shared<std::vector<ObjectId>>();
|
||||||
auto visitor = [&](const MWWorld::Ptr& ptr) {
|
auto visitor = [&](const MWWorld::Ptr& ptr) {
|
||||||
if (ptr.getRefData().isDeleted())
|
if (ptr.getRefData().isDeleted())
|
||||||
|
|
|
@ -34,6 +34,21 @@
|
||||||
#include "types/types.hpp"
|
#include "types/types.hpp"
|
||||||
#include "uibindings.hpp"
|
#include "uibindings.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
struct CellsStore
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sol
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct is_automagical<MWLua::CellsStore> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -68,7 +83,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
auto* lua = context.mLua;
|
auto* lua = context.mLua;
|
||||||
sol::table api(lua->sol(), sol::create);
|
sol::table api(lua->sol(), sol::create);
|
||||||
api["API_REVISION"] = 37;
|
api["API_REVISION"] = 38;
|
||||||
api["quit"] = [lua]() {
|
api["quit"] = [lua]() {
|
||||||
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
|
||||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||||
|
@ -106,17 +121,58 @@ namespace MWLua
|
||||||
return LuaUtil::makeReadOnly(api);
|
return LuaUtil::makeReadOnly(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) };
|
||||||
|
};
|
||||||
|
api["getExteriorCell"] = [](int x, int y, sol::object cellOrName) {
|
||||||
|
ESM::RefId worldspace;
|
||||||
|
if (cellOrName.is<GCell>())
|
||||||
|
worldspace = cellOrName.as<GCell>().mStore->getCell()->getWorldSpace();
|
||||||
|
else if (cellOrName.is<std::string_view>() && !cellOrName.as<std::string_view>().empty())
|
||||||
|
worldspace = MWBase::Environment::get()
|
||||||
|
.getWorldModel()
|
||||||
|
->getCell(cellOrName.as<std::string_view>())
|
||||||
|
.getCell()
|
||||||
|
->getWorldSpace();
|
||||||
|
else
|
||||||
|
worldspace = ESM::Cell::sDefaultWorldspaceId;
|
||||||
|
return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior(
|
||||||
|
ESM::ExteriorCellLocation(x, y, worldspace), /*forceLoad=*/false) };
|
||||||
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
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) -> GCell {
|
||||||
|
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) };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ESM4::Cell* cellRecord = cells4Store->at(index - cells3Store->getSize());
|
||||||
|
return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(
|
||||||
|
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>();
|
||||||
|
api["cells"] = CellsStore{};
|
||||||
|
}
|
||||||
|
|
||||||
static sol::table initWorldPackage(const Context& context)
|
static sol::table initWorldPackage(const Context& context)
|
||||||
{
|
{
|
||||||
sol::table api(context.mLua->sol(), sol::create);
|
sol::table api(context.mLua->sol(), sol::create);
|
||||||
WorldView* worldView = context.mWorldView;
|
WorldView* worldView = context.mWorldView;
|
||||||
addTimeBindings(api, context, true);
|
addTimeBindings(api, context, true);
|
||||||
api["getCellByName"]
|
addCellGetters(api, context);
|
||||||
= [](std::string_view name) { return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name) }; };
|
|
||||||
api["getExteriorCell"] = [](int x, int y) {
|
|
||||||
return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior(
|
|
||||||
ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId)) };
|
|
||||||
};
|
|
||||||
api["activeActors"] = GObjectList{ worldView->getActorsInScene() };
|
api["activeActors"] = GObjectList{ worldView->getActorsInScene() };
|
||||||
api["createObject"] = [](std::string_view recordId, sol::optional<int> count) -> GObject {
|
api["createObject"] = [](std::string_view recordId, sol::optional<int> count) -> GObject {
|
||||||
// Doesn't matter which cell to use because the new object will be in disabled state.
|
// Doesn't matter which cell to use because the new object will be in disabled state.
|
||||||
|
|
|
@ -413,6 +413,14 @@ namespace MWWorld
|
||||||
size_t getExtSize() const;
|
size_t getExtSize() const;
|
||||||
size_t getIntSize() const;
|
size_t getIntSize() const;
|
||||||
|
|
||||||
|
const ESM::Cell* at(size_t index) const
|
||||||
|
{
|
||||||
|
if (index < mSharedInt.size())
|
||||||
|
return mSharedInt.at(index);
|
||||||
|
else
|
||||||
|
return mSharedExt.at(index - mSharedInt.size());
|
||||||
|
}
|
||||||
|
|
||||||
void listIdentifier(std::vector<ESM::RefId>& list) const override;
|
void listIdentifier(std::vector<ESM::RefId>& list) const override;
|
||||||
|
|
||||||
ESM::Cell* insert(const ESM::Cell& cell);
|
ESM::Cell* insert(const ESM::Cell& cell);
|
||||||
|
|
|
@ -160,7 +160,7 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation cellIndex)
|
MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation cellIndex, bool forceLoad)
|
||||||
{
|
{
|
||||||
std::map<ESM::ExteriorCellLocation, CellStore*>::iterator result;
|
std::map<ESM::ExteriorCellLocation, CellStore*>::iterator result;
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation c
|
||||||
result = mExteriors.emplace(cellIndex, cellStore).first;
|
result = mExteriors.emplace(cellIndex, cellStore).first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result->second->getState() != CellStore::State_Loaded)
|
if (forceLoad && result->second->getState() != CellStore::State_Loaded)
|
||||||
{
|
{
|
||||||
result->second->load();
|
result->second->load();
|
||||||
}
|
}
|
||||||
|
@ -234,22 +234,20 @@ MWWorld::CellStore* MWWorld::WorldModel::getInteriorOrNull(std::string_view name
|
||||||
return nullptr; // Cell not found
|
return nullptr; // Cell not found
|
||||||
result = mInteriors.emplace(name, newCellStore).first;
|
result = mInteriors.emplace(name, newCellStore).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result->second->getState() != CellStore::State_Loaded)
|
|
||||||
result->second->load();
|
|
||||||
|
|
||||||
return result->second;
|
return result->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CellStore& MWWorld::WorldModel::getInterior(std::string_view name)
|
MWWorld::CellStore& MWWorld::WorldModel::getInterior(std::string_view name, bool forceLoad)
|
||||||
{
|
{
|
||||||
CellStore* res = getInteriorOrNull(name);
|
CellStore* res = getInteriorOrNull(name);
|
||||||
if (res == nullptr)
|
if (res == nullptr)
|
||||||
throw std::runtime_error("Interior not found: '" + std::string(name) + "'");
|
throw std::runtime_error("Interior not found: '" + std::string(name) + "'");
|
||||||
|
if (forceLoad && res->getState() != CellStore::State_Loaded)
|
||||||
|
res->load();
|
||||||
return *res;
|
return *res;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id)
|
MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id, bool forceLoad)
|
||||||
{
|
{
|
||||||
auto result = mCells.find(id);
|
auto result = mCells.find(id);
|
||||||
if (result != mCells.end())
|
if (result != mCells.end())
|
||||||
|
@ -257,7 +255,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id)
|
||||||
|
|
||||||
if (const auto* exteriorId = id.getIf<ESM::ESM3ExteriorCellRefId>())
|
if (const auto* exteriorId = id.getIf<ESM::ESM3ExteriorCellRefId>())
|
||||||
return getExterior(
|
return getExterior(
|
||||||
ESM::ExteriorCellLocation(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId));
|
ESM::ExteriorCellLocation(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId),
|
||||||
|
forceLoad);
|
||||||
|
|
||||||
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().search(id);
|
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().search(id);
|
||||||
CellStore* newCellStore = nullptr;
|
CellStore* newCellStore = nullptr;
|
||||||
|
@ -281,17 +280,21 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id)
|
||||||
{
|
{
|
||||||
mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore);
|
mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore);
|
||||||
}
|
}
|
||||||
if (newCellStore->getState() != CellStore::State_Loaded)
|
if (forceLoad && newCellStore->getState() != CellStore::State_Loaded)
|
||||||
{
|
{
|
||||||
newCellStore->load();
|
newCellStore->load();
|
||||||
}
|
}
|
||||||
return *newCellStore;
|
return *newCellStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name)
|
MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name, bool forceLoad)
|
||||||
{
|
{
|
||||||
if (CellStore* res = getInteriorOrNull(name)) // first try interiors
|
if (CellStore* res = getInteriorOrNull(name)) // first try interiors
|
||||||
|
{
|
||||||
|
if (forceLoad && res->getState() != CellStore::State_Loaded)
|
||||||
|
res->load();
|
||||||
return *res;
|
return *res;
|
||||||
|
}
|
||||||
|
|
||||||
// try named exteriors
|
// try named exteriors
|
||||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().searchExtByName(name);
|
const ESM::Cell* cell = mStore.get<ESM::Cell>().searchExtByName(name);
|
||||||
|
@ -319,7 +322,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name)
|
||||||
if (!cell)
|
if (!cell)
|
||||||
throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name));
|
throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name));
|
||||||
|
|
||||||
return getExterior(ESM::ExteriorCellLocation(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId));
|
return getExterior(
|
||||||
|
ESM::ExteriorCellLocation(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId), forceLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition(
|
MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition(
|
||||||
|
|
|
@ -65,10 +65,10 @@ namespace MWWorld
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
CellStore& getExterior(ESM::ExteriorCellLocation cellIndex);
|
CellStore& getExterior(ESM::ExteriorCellLocation cellIndex, bool forceLoad = true);
|
||||||
CellStore& getInterior(std::string_view name);
|
CellStore& getInterior(std::string_view name, bool forceLoad = true);
|
||||||
CellStore& getCell(std::string_view name); // interior or named exterior
|
CellStore& getCell(std::string_view name, bool forceLoad = true); // interior or named exterior
|
||||||
CellStore& getCell(const ESM::RefId& Id);
|
CellStore& getCell(const ESM::RefId& Id, bool forceLoad = true);
|
||||||
|
|
||||||
// Returns the cell that is in the same worldspace as `cellInSameWorldSpace`
|
// Returns the cell that is in the same worldspace as `cellInSameWorldSpace`
|
||||||
// (in case of nullptr - default exterior worldspace) and contains given position.
|
// (in case of nullptr - default exterior worldspace) and contains given position.
|
||||||
|
|
|
@ -225,6 +225,7 @@
|
||||||
-- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the wheather).
|
-- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the wheather).
|
||||||
-- @field #number gridX Index of the cell by X (only for exteriors).
|
-- @field #number gridX Index of the cell by X (only for exteriors).
|
||||||
-- @field #number gridY Index of the cell by Y (only for exteriors).
|
-- @field #number gridY Index of the cell by Y (only for exteriors).
|
||||||
|
-- @field #string worldSpaceId Id of the world space.
|
||||||
-- @field #boolean hasWater True if the cell contains water.
|
-- @field #boolean hasWater True if the cell contains water.
|
||||||
-- @field #boolean hasSky True if in this cell sky should be rendered.
|
-- @field #boolean hasSky True if in this cell sky should be rendered.
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,14 @@
|
||||||
-- @function [parent=#world] getExteriorCell
|
-- @function [parent=#world] getExteriorCell
|
||||||
-- @param #number gridX
|
-- @param #number gridX
|
||||||
-- @param #number gridY
|
-- @param #number gridY
|
||||||
|
-- @param #any cellOrName (optional) other cell or cell name in the same exterior world space
|
||||||
-- @return openmw.core#Cell
|
-- @return openmw.core#Cell
|
||||||
|
|
||||||
|
---
|
||||||
|
-- List of all cells
|
||||||
|
-- @field [parent=#world] #list<openmw.core#Cell> cells
|
||||||
|
-- @usage for i, cell in ipairs(world.cells) do print(cell) end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Simulation time in seconds.
|
-- Simulation time in seconds.
|
||||||
-- The number of simulation seconds passed in the game world since starting a new game.
|
-- The number of simulation seconds passed in the game world since starting a new game.
|
||||||
|
|
Loading…
Reference in a new issue