Additional Lua bindings for cells

simplify_debugging
Petr Mikheev 2 years ago
parent 2725a9d7f4
commit ce7f6f31c9

@ -33,7 +33,8 @@ namespace MWLua
auto cell = c.mStore->getCell();
std::stringstream res;
if (cell->isExterior())
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")";
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ", "
<< cell->getWorldSpace().toDebugString() << ")";
else
res << "interior(" << cell->getNameId() << ")";
return res.str();
@ -42,6 +43,8 @@ namespace MWLua
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); });
cellT["region"] = sol::readonly_property(
[](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["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(); });
@ -67,13 +70,15 @@ namespace MWLua
if (!ptr.isInCell())
return false;
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>)
{ // only for global scripts
cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
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>>();
auto visitor = [&](const MWWorld::Ptr& ptr) {
if (ptr.getRefData().isDeleted())

@ -34,6 +34,21 @@
#include "types/types.hpp"
#include "uibindings.hpp"
namespace MWLua
{
struct CellsStore
{
};
}
namespace sol
{
template <>
struct is_automagical<MWLua::CellsStore> : std::false_type
{
};
}
namespace MWLua
{
@ -68,7 +83,7 @@ namespace MWLua
{
auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create);
api["API_REVISION"] = 37;
api["API_REVISION"] = 38;
api["quit"] = [lua]() {
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();
MWBase::Environment::get().getStateManager()->requestQuit();
@ -106,17 +121,58 @@ namespace MWLua
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)
{
sol::table api(context.mLua->sol(), sol::create);
WorldView* worldView = context.mWorldView;
addTimeBindings(api, context, true);
api["getCellByName"]
= [](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)) };
};
addCellGetters(api, context);
api["activeActors"] = GObjectList{ worldView->getActorsInScene() };
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.

@ -413,6 +413,14 @@ namespace MWWorld
size_t getExtSize() 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;
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;
@ -211,7 +211,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation c
result = mExteriors.emplace(cellIndex, cellStore).first;
}
}
if (result->second->getState() != CellStore::State_Loaded)
if (forceLoad && result->second->getState() != CellStore::State_Loaded)
{
result->second->load();
}
@ -234,22 +234,20 @@ MWWorld::CellStore* MWWorld::WorldModel::getInteriorOrNull(std::string_view name
return nullptr; // Cell not found
result = mInteriors.emplace(name, newCellStore).first;
}
if (result->second->getState() != CellStore::State_Loaded)
result->second->load();
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);
if (res == nullptr)
throw std::runtime_error("Interior not found: '" + std::string(name) + "'");
if (forceLoad && res->getState() != CellStore::State_Loaded)
res->load();
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);
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>())
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);
CellStore* newCellStore = nullptr;
@ -281,17 +280,21 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id)
{
mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore);
}
if (newCellStore->getState() != CellStore::State_Loaded)
if (forceLoad && newCellStore->getState() != CellStore::State_Loaded)
{
newCellStore->load();
}
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 (forceLoad && res->getState() != CellStore::State_Loaded)
res->load();
return *res;
}
// try named exteriors
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)
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(

@ -65,10 +65,10 @@ namespace MWWorld
void clear();
CellStore& getExterior(ESM::ExteriorCellLocation cellIndex);
CellStore& getInterior(std::string_view name);
CellStore& getCell(std::string_view name); // interior or named exterior
CellStore& getCell(const ESM::RefId& Id);
CellStore& getExterior(ESM::ExteriorCellLocation cellIndex, bool forceLoad = true);
CellStore& getInterior(std::string_view name, bool forceLoad = true);
CellStore& getCell(std::string_view name, bool forceLoad = true); // interior or named exterior
CellStore& getCell(const ESM::RefId& Id, bool forceLoad = true);
// Returns the cell that is in the same worldspace as `cellInSameWorldSpace`
// (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 #number gridX Index of the cell by X (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 hasSky True if in this cell sky should be rendered.

@ -21,8 +21,14 @@
-- @function [parent=#world] getExteriorCell
-- @param #number gridX
-- @param #number gridY
-- @param #any cellOrName (optional) other cell or cell name in the same exterior world space
-- @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.
-- The number of simulation seconds passed in the game world since starting a new game.

Loading…
Cancel
Save