1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 03:35:27 +00:00

Merge branch 'coc_destination' into 'master'

Improve coc destination search in ESM4 cells

See merge request OpenMW/openmw!3034
This commit is contained in:
psi29a 2023-05-21 17:33:36 +00:00
commit 458ee4abaa
2 changed files with 82 additions and 41 deletions

View File

@ -285,6 +285,7 @@ namespace MWWorld
// NOTE: does not account for moved references // NOTE: does not account for moved references
// Should be phased out when we have const version of forEach // Should be phased out when we have const version of forEach
inline const CellRefList<ESM::Door>& getReadOnlyDoors() const { return get<ESM::Door>(); } inline const CellRefList<ESM::Door>& getReadOnlyDoors() const { return get<ESM::Door>(); }
inline const CellRefList<ESM4::Door>& getReadOnlyEsm4Doors() const { return get<ESM4::Door>(); }
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const { return get<ESM::Static>(); } inline const CellRefList<ESM::Static>& getReadOnlyStatics() const { return get<ESM::Static>(); }
inline const CellRefList<ESM4::Static>& getReadOnlyEsm4Statics() const { return get<ESM4::Static>(); } inline const CellRefList<ESM4::Static>& getReadOnlyEsm4Statics() const { return get<ESM4::Static>(); }

View File

@ -25,6 +25,7 @@
#include <components/esm3/loadregn.hpp> #include <components/esm3/loadregn.hpp>
#include <components/esm3/loadstat.hpp> #include <components/esm3/loadstat.hpp>
#include <components/esm4/loadcell.hpp> #include <components/esm4/loadcell.hpp>
#include <components/esm4/loaddoor.hpp>
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
@ -2632,20 +2633,30 @@ namespace MWWorld
physicActor->enableCollisionBody(enable); physicActor->enableCollisionBody(enable);
} }
ESM::RefId World::findInteriorPosition(std::string_view name, ESM::Position& pos) static std::optional<ESM::Position> searchMarkerPosition(const CellStore& cellStore, std::string_view editorId)
{ {
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; for (const MWWorld::LiveCellRef<ESM4::Static>& stat4 : cellStore.getReadOnlyEsm4Statics().mList)
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; {
if (Misc::StringUtils::lowerCase(stat4.mBase->mEditorId) == editorId)
MWWorld::CellStore& cellStore = mWorldModel.getInterior(name); return stat4.mRef.getPosition();
}
return std::nullopt;
}
static std::optional<ESM::Position> searchDoorDestInCell(const CellStore& cellStore)
{
ESM::RefId cellId = cellStore.getCell()->getId(); ESM::RefId cellId = cellStore.getCell()->getId();
std::vector<const MWWorld::CellRef*> sortedDoors; std::vector<const MWWorld::CellRef*> sortedDoors;
for (const MWWorld::LiveCellRef<ESM::Door>& door : cellStore.getReadOnlyDoors().mList) for (const MWWorld::LiveCellRef<ESM::Door>& door : cellStore.getReadOnlyDoors().mList)
{ {
if (!door.mRef.getTeleport()) if (!door.mRef.getTeleport())
continue; continue;
sortedDoors.push_back(&door.mRef);
}
for (const MWWorld::LiveCellRef<ESM4::Door>& door : cellStore.getReadOnlyEsm4Doors().mList)
{
if (!door.mRef.getTeleport())
continue;
sortedDoors.push_back(&door.mRef); sortedDoors.push_back(&door.mRef);
} }
@ -2657,34 +2668,54 @@ namespace MWWorld
return lhs->getDestCell() < rhs->getDestCell(); return lhs->getDestCell() < rhs->getDestCell();
}); });
WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
for (const MWWorld::CellRef* door : sortedDoors) for (const MWWorld::CellRef* door : sortedDoors)
{ {
MWWorld::CellStore& source = mWorldModel.getCell(door->getDestCell()); const MWWorld::CellStore& source = worldModel->getCell(door->getDestCell());
// Find door leading to our current teleport door // Find door leading to our current teleport door
// and use its destination to position inside cell. // and use its destination to position inside cell.
// \note Using _any_ door pointed to the cell,
// not the one pointed to current door.
for (const MWWorld::LiveCellRef<ESM::Door>& destDoor : source.getReadOnlyDoors().mList) for (const MWWorld::LiveCellRef<ESM::Door>& destDoor : source.getReadOnlyDoors().mList)
{ {
if (name == destDoor.mRef.getDestCell()) if (cellId == destDoor.mRef.getDestCell())
{ return destDoor.mRef.getDoorDest();
/// \note Using _any_ door pointed to the interior,
/// not the one pointed to current door.
pos = destDoor.mRef.getDoorDest();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return cellId;
}
} }
} for (const MWWorld::LiveCellRef<ESM4::Door>& destDoor : source.getReadOnlyEsm4Doors().mList)
for (const MWWorld::LiveCellRef<ESM4::Static>& stat4 : cellStore.getReadOnlyEsm4Statics().mList)
{
if (Misc::StringUtils::lowerCase(stat4.mBase->mEditorId) == "cocmarkerheading")
{ {
// found the COC position? if (cellId == destDoor.mRef.getDestCell())
pos = stat4.mRef.getPosition(); return destDoor.mRef.getDoorDest();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return cellId;
} }
} }
return std::nullopt;
}
ESM::RefId World::findInteriorPosition(std::string_view name, ESM::Position& pos)
{
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
const MWWorld::CellStore& cellStore = mWorldModel.getInterior(name);
ESM::RefId cellId = cellStore.getCell()->getId();
if (std::optional<ESM::Position> destPos = searchMarkerPosition(cellStore, "cocmarkerheading"))
{
pos = *destPos;
return cellId;
}
if (std::optional<ESM::Position> destPos = searchDoorDestInCell(cellStore))
{
pos = *destPos;
return cellId;
}
if (std::optional<ESM::Position> destPos = searchMarkerPosition(cellStore, "xmarkerheading"))
{
pos = *destPos;
return cellId;
}
// Fall back to the first static location. // Fall back to the first static location.
const MWWorld::CellRefList<ESM4::Static>::List& statics4 = cellStore.getReadOnlyEsm4Statics().mList; const MWWorld::CellRefList<ESM4::Static>::List& statics4 = cellStore.getReadOnlyEsm4Statics().mList;
if (!statics4.empty()) if (!statics4.empty())
@ -2693,7 +2724,6 @@ namespace MWWorld
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return cellId; return cellId;
} }
// Fall back to the first static location.
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore.getReadOnlyStatics().mList; const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore.getReadOnlyStatics().mList;
if (!statics.empty()) if (!statics.empty())
{ {
@ -2709,17 +2739,17 @@ namespace MWWorld
{ {
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
const MWWorld::Cell* ext = nullptr; const MWWorld::CellStore* cellStore = nullptr;
try try
{ {
ext = mWorldModel.getCell(nameId).getCell(); cellStore = &mWorldModel.getCell(nameId);
if (!ext->isExterior()) if (!cellStore->isExterior())
return ESM::RefId(); return ESM::RefId();
} }
catch (std::exception&) catch (std::exception&)
{ {
} }
if (!ext) if (!cellStore)
{ {
size_t comma = nameId.find(','); size_t comma = nameId.find(',');
if (comma != std::string::npos) if (comma != std::string::npos)
@ -2731,28 +2761,38 @@ namespace MWWorld
if (xResult.ec == std::errc::result_out_of_range || yResult.ec == std::errc::result_out_of_range) if (xResult.ec == std::errc::result_out_of_range || yResult.ec == std::errc::result_out_of_range)
throw std::runtime_error("Cell coordinates out of range."); throw std::runtime_error("Cell coordinates out of range.");
else if (xResult.ec == std::errc{} && yResult.ec == std::errc{}) else if (xResult.ec == std::errc{} && yResult.ec == std::errc{})
ext = mWorldModel.getExterior(ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId)) cellStore
.getCell(); = &mWorldModel.getExterior(ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId));
// ignore std::errc::invalid_argument, as this means that name probably refers to a interior cell // ignore std::errc::invalid_argument, as this means that name probably refers to a interior cell
// instead of comma separated coordinates // instead of comma separated coordinates
} }
} }
if (ext) if (!cellStore)
return ESM::RefId();
const MWWorld::Cell* ext = cellStore->getCell();
if (std::optional<ESM::Position> destPos = searchMarkerPosition(*cellStore, "cocmarkerheading"))
{ {
int x = ext->getGridX(); pos = *destPos;
int y = ext->getGridY(); return ext->getId();
osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellLocation(x, y, ext->getWorldSpace()), true); }
pos.pos[0] = posFromIndex.x(); if (std::optional<ESM::Position> destPos = searchMarkerPosition(*cellStore, "xmarkerheading"))
pos.pos[1] = posFromIndex.y(); {
pos = *destPos;
// Note: Z pos will be adjusted by adjustPosition later
pos.pos[2] = 0;
return ext->getId(); return ext->getId();
} }
return ESM::RefId(); int x = ext->getGridX();
int y = ext->getGridY();
osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellLocation(x, y, ext->getWorldSpace()), true);
pos.pos[0] = posFromIndex.x();
pos.pos[1] = posFromIndex.y();
// Note: Z pos will be adjusted by adjustPosition later
pos.pos[2] = 0;
return ext->getId();
} }
void World::enableTeleporting(bool enable) void World::enableTeleporting(bool enable)